twoSum Algorithm : How to improve this? - java

I felt like doing an algorithm and found this problem on leetcode
Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
My solution is O(n^2). I wanted to know if there is better way of doing this? like O(n) or O(nlogn)
import java.util.Arrays;
public class ReturnIndex {
public int[] twoSum(int[] numbers, int target) {
int tail = numbers.length-1;
int[] n = new int[2];
for (int i=0;i<tail;i++) {
for(int j=i+1;j<tail;j++) {
if(target ==(numbers[i]+numbers[j])) {
n[0] = i+1;
n[1] = j+1;
}
}
}
return n;
}
public static void main(String[] args) {
int[] s = {150,24,79,50,88,345,3};
int value = 200;
ReturnIndex r = new ReturnIndex();
int[] a = r.twoSum(s,value);
System.out.println(Arrays.toString(a));
}
}

Sort the array. Make two pointers point at first and last (x and X). Run this in a loop:
if (a[X]+a[x] > N) then X--
else if (a[X]+a[x] < N) then x++
else if (a[X]+a[x] == N) then found.
if (x > X) then no numbers exist.
O(nlogn) time, O(1) memory

O(n log n) time, O(1) memory (not counting the list):
First, sort the list. This should take O(n log n) time, as most sort functions do.
Iterate through the list, which should take O(n) time in the outer loop. At this point you can do a binary search for the closest matching integer in a sorted sublist, which should take O(log n) time. This stage should wind up taking O(n log n) total.
Edit: Check out Max's answer below. It's still O(n log n) time and O(1) memory, but he avoids the binary searches by walking a pointer from each end of the list.
O(n) time, O(n) memory:
Build a hash table, which should have O(1) insertion and O(1) contains. Then, in a O(n) outer loop, for each number i, check if total - i is in the hash table. If not, add it; if so, then you've got your two numbers.
Either way, you would need an additional scan through the array to get the indices, but that's no problem--it only takes O(n) time. If you wanted to avoid it you could keep the original index in the sorted list or hash table as needed, but that has a memory footprint instead of a time footprint.

Below you can find a solution in which the two numbers could be found in O(n log n) time:
1- Sort the numbers in ascending (or descending) order // O(n log n)
2- Compute diff = target - item for each item // O(n)
3- For each calculated diff, look up the calculated value in the sorted items
using the Binary search algorithm // O(n log n)
A complete, working implementation in Java:
import java.util.ArrayList;
public class NumbersFinder {
class Item{
private int value;
private int index;
public Item(int value, int index){
this.value = value;
this.index = index;
}
public int getValue(){
return value;
}
public int getIndex(){
return index;
}
}
public ArrayList<Item> find(int[] values, int target){
ArrayList<Item> items = new ArrayList<Item>();
for(int i = 0; i < values.length; i++)
items.add(new Item(values[i], i));
items = quicksort(items);
ArrayList<Integer> diffs = computeDiffs(items, target);
Item item1 = null;
Item item2 = null;
boolean found = false;
for(int i = 0; i < diffs.get(i) && !found; i++){
item1 = items.get(i);
item2 = searchSortedItems(items, diffs.get(i), 0, items.size());
found = item2 != null;
}
if(found){
ArrayList<Item> result = new ArrayList<Item>();
result.add(item1);
result.add(item2);
return result;
}
else
return null;
}
// find "value" in the sorted array of "items" using Binary search in O(log n)
private Item searchSortedItems(ArrayList<Item> items, Integer value, int lower, int upper) {
if(lower > upper)
return null;
int middle = (lower + upper)/2;
Item middleItem = items.get(middle);
if(middleItem.getValue() == value)
return middleItem;
else if(middleItem.getValue() < value)
return searchSortedItems(items, value, middle+1, upper);
else
return searchSortedItems(items, value, lower, middle-1);
}
// Simply calculates difference between the target value and each item in the array; O(n)
private ArrayList<Integer> computeDiffs(ArrayList<Item> items, int target) {
ArrayList<Integer> diffs = new ArrayList<Integer>();
for(int i = 0; i < items.size(); i++)
diffs.add(target - items.get(i).getValue());
return diffs;
}
// Sorts items using QuickSort algorithm in O(n Log n)
private ArrayList<Item> quicksort(ArrayList<Item> items) {
if (items.size() <= 1)
return items;
int pivot = items.size() / 2;
ArrayList<Item> lesser = new ArrayList<Item>();
ArrayList<Item> greater = new ArrayList<Item>();
int sameAsPivot = 0;
for (Item item : items) {
if (item.getValue() > items.get(pivot).getValue())
greater.add(item);
else if (item.getValue() < items.get(pivot).getValue())
lesser.add(item);
else
sameAsPivot++;
}
lesser = quicksort(lesser);
for (int i = 0; i < sameAsPivot; i++)
lesser.add(items.get(pivot));
greater = quicksort(greater);
ArrayList<Item> sorted = new ArrayList<Item>();
for (Item item : lesser)
sorted.add(item);
for (Item item: greater)
sorted.add(item);
return sorted;
}
public static void main(String[] args){
int[] s = {150,24,79,50,88,345,3};
int value = 200;
NumbersFinder finder = new NumbersFinder();
ArrayList<Item> numbers = finder.find(s, value);
if(numbers != null){
System.out.println("First Number Found = " + numbers.get(0).getValue() + " ; Index = " + + numbers.get(0).getIndex());
System.out.println("Second Number Found = " + numbers.get(1).getValue() + " ; Index = " + + numbers.get(1).getIndex());
}
else{
System.out.println("No such two numbers found in the array!");
}
}
}
Output:
First Number Found = 50 ; Index = 3
Second Number Found = 150 ; Index = 0

One line solution in python :
class Solution(object):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
def twoSum(self, nums, target):
x = [[i, nums.index(target-j)] for i,j in enumerate(nums) if nums.count(target-j) > 0 and nums.index(target-j)!=i]
return x.pop()

Can provide an O(n) time solution, but his memory cannot be O(1)
First you declare a key-value pair , where key is the value in the array of integers and value is the index in the array of integers. And, you need to declare a hash table to hold the key-value pairs.
Then you need to iterate through the entire array of integers,
if the value of this array (=sum - array[i]) is in the hash table, congratulations you found it,
if not, it is stored in the hash table.
So the entire time spent is the time to insert and query the hash table.
Memory is the size of the hash table.
My English is not very good, I hope I can help you.
public static void main(String args[]) {
int[] array = {150,24,79,50,88,345,3};
int sum = 200;
Map<Integer,Integer> table = new HashMap<>();
StringBuilder builder = new StringBuilder();
for(int i=0;i<array.length;i++){
int key = sum - array[i];
if(table.containsKey(key)){
builder.append("index1=").append(table.get(key)).
append(" index2=").append(i);
}else{
table.put(array[i],i);
}
}
System.out.println(builder);
}

As #Prayer mentioned above, here is the accepted answer.
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] resultarray=new int[2];
for (int i=0;i<nums.length-1;i++){
for(int k=i+1;k<nums.length;k++)
{
if(target==nums[i]+nums[k])
{
resultarray[0]=i;
resultarray[1]=k;
}
}
}
return resultarray;
}
}

The naïve solution to the two-sum problem is O(n^2), s.t. n is the length of the array of numbers provided.
However, we can do better by using a hash-map of the values seen so far (key=number, value=index) and checking if the complement is already there (O(1)) as we iterate over the numbers. This approach is optimal for an unsorted array:
Runtime complexity: O(n)
Space complexity: O(n) -- though if there is a solution, in practice this would be O(n/2)
Given the OP's question:
does not specify whether the input array is sorted or not (it is, therefore, safe to assume the input array can be anything), and
specifically asks for indexes of the provided array, as opposed to the actual numbers, any kind of solution sorting the array would need to copy it beforehand, keep a mapping of indexes between the sorted array and the unsorted one, or iterate over the original array, hence costing memory (O(n)) or time (O(n)), depending on the approach chosen. Therefore, the 1st part of the (currently) accepted solution is, strictly speaking, incorrect.
Optimal solution:
In Python:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
seen = {}
for j, num in enumerate(nums):
i = seen.get(target-num, -1)
if i != -1:
return [i+1, j+1]
seen[num] = j
return [-1, -1]
In Java:
import java.util.Map;
import java.util.HashMap;
public class Solution {
public int[] twoSum(int[] nums, int target) {
final Map<Integer, Integer> seen = new HashMap<>();
for (int j = 0; j < nums.length; ++j) {
final Integer i = seen.get(target - nums[j]); // One hash-map access v.s. two when using contains beforehand.
if (i != null) {
return new int[]{ i+1, j+1 };
}
numbers.put(nums[j], j);
}
return new int[]{-1, -1};
}
}
Note that by construction, if the complement is present in the map/dictionary, then the index stored will always be lower than the current index. Hence the following proposition is verified:
index1 must be less than index2
Also note that the OP's question needed 1-based indexes, which is what I've provided above, but the Leetcode question referred to seems to have been updated since then, and now is 0-based: https://leetcode.com/problems/two-sum.
I hope this helps.

Here is an O(n):
public int[] findSumMatched(int[] numbers, int target) {
Map<Integer, Integer> mapOfNumbers = new HashMap<Integer, Integer>();
for (int i = 0; i<numbers.length; i++) {
int secondNumber = target - numbers[i];
if (mapOfNumbers.get(secondNumber) != null){
return new int[] {mapOfNumbers.get(secondNumber), i};
}
mapOfNumbers.put(numbers[i], i);
}
throw new IllegalArgumentException();
}

class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
out_list=[]
for i in range(len(nums)):
for j in range(len(nums)):
if(target-nums[i]) == nums[j] and i != j:
out_list.append(i)
return out_list

I would approach it this way:
Order your array from smaller to lower value
Loop over your array the way you have it but exit the loop early whenever
target <(numbers[i]+numbers[j])
Once you have the value of your two elements such that n[0] + n[1] = target, look back at the original array to find their index.

Here is my cpp solution with O(nlog(n)):
vector<int> two_sum(vector<int> &numbers, int target) {
vector<int> result;
vector<int> numbers_dup = vector<int>(numbers);
sort(numbers_dup.begin(), numbers_dup.end());
int left = 0, right = numbers_dup.size() - 1;
while(left <= right) {
int sum = numbers_dup[left] + numbers_dup[right];
if(sum == target) {
//find the idex of numbers_dup[left] and numbers_dup[right]
for(int i = 0; i < numbers.size(); i++) {
if(numbers[i] == numbers_dup[left] || numbers[i] == numbers_dup[right]) {
result.push_back(i);
}
if(result.size() == 2) {
return result;
}
}
}
else if(sum > target) {
right--;
}
else {
left++;
}
}
}
Check out my blog for the detailed explanation.
https://algorithm.pingzhang.io/Array/two_sum_problem.html

Here is the answer using HashMap in java with two passes of the array. Assuming that there are no duplicate elements in the array and there is exactly one solution exists.
import java.util.HashMap;
public class TwoSum {
int[] index = new int[2];
public int[] twoSum(int[] nums, int target)
{
int length = nums.length;
//initialize return values assuming that pair for the given target
//doesn't exist
index[0]=-1;
index[1]=-1;
//sanity check
if(length<1) return index;
HashMap<Integer, Integer> numHash = new HashMap<>(length);
//get the values from array into HashMap assuming that there aren't duplicate values
for(int i=0; i<length;i++)
{
numHash.put(nums[i],i);
}
//check for the value in the array and the difference between target and it. Assume that only
//one such pair exists
for(int i=0;i<length;i++)
{
int val1 = nums[i];
int val2=target-val1;
//make sure that it doesn't return the index of the first number in the pait you are searching for
if( numHash.containsKey(val2) && numHash.get(val2)!=i){
index[0]=i;
index[1] =numHash.get(target-nums[i]);
break;
}
}
return index;
}
}

public static int[] twoSum(int[] nums, int target) {
int []resultarray=new int[2];
for (int i=0;i<nums.length-1;i++){
for(int k=1;k<nums.length;k++)
{
if(target==nums[i]+nums[k])
{
resultarray[0]=nums[i];
resultarray[1]=nums[k];
}
}
}
return resultarray;
}

This is my python solution
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
copy_dict = {}
for pos in range(0, len(nums)):
if nums[pos] not in copy_dict.keys():
copy_dict[nums[pos]] = [pos]
else:
copy_dict[nums[pos]].append(pos)
def get_sum_indexes(sorted_array, target):
right_pointer = len(sorted_array) - 1
left_pointer = 0
while left_pointer < len(sorted_array) or right_pointer > 0:
if sorted_array[right_pointer] + sorted_array[left_pointer] == target:
return [sorted_array[left_pointer], sorted_array[right_pointer]]
elif sorted_array[right_pointer] + sorted_array[left_pointer] > target:
right_pointer -= 1
elif sorted_array[right_pointer] + sorted_array[left_pointer] < target:
left_pointer += 1
return None
sum_numbers = get_sum_indexes(sorted(nums), target)
if len(copy_dict[sum_numbers[0]]) == 1:
answer_1 = copy_dict[sum_numbers[0]][0]
else:
answer_1 = copy_dict[sum_numbers[0]][0]
if len(copy_dict[sum_numbers[1]]) == 1:
answer_2 = copy_dict[sum_numbers[1]][0]
else:
answer_2 = copy_dict[sum_numbers[1]][1]
return sorted([answer_1, answer_2])
print(Solution().twoSum(nums=[-1, -2, -3, -4, -5], target=-8))
print(Solution().twoSum(nums=[-3, -3], target=-6))

Sort the list in non-decreasing order. It takes O(nlogn) time complexity.
Find the two numbers, which can be done in O(n) time.
Find the two indices of the two numbers, which can be done in O(n) time.
Overall complexity is O(nlogn).
Implementation in python:
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
p = nums[:]
p.sort() #sorting in -> O(nlogn)
r = len(nums)-1
l =0
#find the indices -> O(n)
for i in range(len(nums)):
if(p[l] + p[r]<target):
l += 1
elif (p[l] + p[r]>target):
r -=1
else :
first_num = p[l]
second_num = p[r]
#find the indices of the numbers -> O(n)
for i in range(len(nums)):
if(nums[i]==first_num):
first_index = i
elif (nums[i]==second_num):
second_index = i
return [first_index,second_index]

Swift code with Time Complexity O(n) and Space complexity O(n):
import UIKit
class Solution{
func twoSum(_ nums: [Int], _ target: Int) -> [Int]{
var finalArray = [Int]()
var newDictionary = [Int:Int]()
for i in 0..<nums.count{
let complement = target - nums[i]
if newDictionary[complement] != nil && newDictionary[complement] != i{
finalArray.append(newDictionary[complement]!)
finalArray.append(i)
return finalArray
}
newDictionary[nums[i]] = i
}
return []
}
}
func main(){
let solution = Solution()
print("All Good" ,solution.twoSum([1, 3, 4 , 5], 6))
}
main()

An O(n) solution in c++ using hash map only exploiting Commutative rule of Addition in real numbers.
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> my_map;
for ( int i = 0 ; i < nums.size(); i++ ){
if(my_map.find(target - nums[i]) != my_map.end()){
return vector<int> {my_map[target - nums[i]], i};
}
my_map[nums[i]] = i ;
}
}
};

I tried most of the answers and they don't seem to handle the edge cases properly. Hence, throwing my two cents for python3 solution that handles the edge cases. I used Max's algorithm to implement it:
def twoSum(nums, target):
output=[]
arr=sorted(nums)
x=0
y=-1
X=len(nums)-1
while x<X:
if (arr[X]+arr[x] > target):
X-=1
elif (arr[X]+arr[x] < target):
x+=1
elif (arr[X]+arr[x] == target):
#print("Found",arr[X],arr[x])
num1=arr[x]
num2=arr[X]
x+=1
X-=1
for i in range(len(nums)):
if num1 == nums[i] and y==-1:
index1=i
y=i
elif num2 == nums[i]:
index2=i
return [index1, index2]
N.B. It's important to consider edge cases and inputs like the following
print(twoSum([3,2,4], 6)) # [1,2]
print(twoSum([3,3], 6)) # [0,1]

Here is an Efficient Solution.
Time Complexity - O(n) and Space Complexity - O(1)
Sol: Will take two-pointer(start_pointer and end_pointer). Initially start_pointer point at the first index and end_pointer point to the last.
Add both the element (sum = array[start_pointer] + array[last_pointer]. After that check, if the sum > target element or not. If yes decrease the end_pointer else increase start_pointer. If sum = target, means you got the indexes.
public int[] twoSum(int[] numbers, int target) {
int[] arr = new int[2]; // to store result
int sum=0;
int start_pointer=0;
int end_pointer = (numbers.length)-1;
while(start_pointer<=end_pointer){
sum=numbers[start_pointer]+numbers[end_pointer];
if(sum>target)
end_pointer-=1;
else if(sum<target)
start_pointer+=1;
else{
arr[0]=start_pointer;
arr[1]=end_pointer;
break;
}
}
return arr;
}

We can do with HashMap and the time complexity would be O(n)
public class ReturnIndicesOfElementsAddToSum {
public static void main(String[] args) {
int[] nums = {2, 7, 11, 15};
int target = 18;
if(!getIndices(nums,target)) {
System.out.println("No such numbers found");
}
}
static boolean getIndices(int[] nums, int target) {
Map<Integer,Integer> indexMap = new HashMap<>();
boolean numFound = false;
for(int i=0;i<nums.length;i++) {
int temp = target - nums[i];
indexMap.put(nums[i], i);
if(indexMap.containsKey(temp)) {
System.out.printf("%d and %d adds upto the target value and indices are %d and %d"
, nums[i], temp, i, indexMap.get(temp));
numFound = true;
}
}
return numFound;
}
}

Using HashMap this is also a solution if complexity for search in HashMap will in order of O(logn) then in worst case the complexity will be O(nlogn)
public int[] twoSum(int[] nums, int target) {
int [] resultIndex = null;
HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i=0;i<nums.length;i++){
int temp = target - nums[i];
if(map.containsKey(temp)){
resultIndex = new int[2];
resultIndex[0]=map.get(temp);
resultIndex[1]=i;
}else{
map.put(nums[i],i);
}
}
return resultIndex;
}

Just curious, but what's wrong with this O(n) solution?
public int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length - 1; i++){
if (nums[i] + nums[i+1] == target)
return new int[] {i, i+1};
}
return null;
}

My solution to this problem would be,
public int[] twoSums(int[] unsortedNum, int target) {
int[] nums = Arrays.copyOf(unsortedNum, unsortedNum.length);
Arrays.sort(nums);
boolean isResultFound = false;
int start = 0;
int end = nums.length-1;
while(!(start > end)) {
if(nums[start]+nums[end] > target){
end--;
} else if (nums[start]+nums[end] < target){
start++;
} else if(nums[start] + nums[end] == target){
isResultFound = true;
break;
}
}
if(isResultFound){
int s = -1;
int e = -1;
for(int i = 0; i< unsortedNum.length; i++){
if(s != -1 && e != -1){
break;
}
if(s == -1 && unsortedNum[i] == nums[start]){
s = i;
} else if(e == -1 && unsortedNum[i] == nums[end]) {
e = i;
}
}
return new int[] {s,e};
}
// for element not found
return new int[]{-1,-1};
}
In the end, if you get -1, -1 as the index then you can say that elements not found which could sum to the target element.

class Solution {
public int[] twoSum(int[] nums, int target) {
int[] sortedNums = Arrays.copyOf(nums, nums.length);
Arrays.sort(sortedNums);
int leftSortedIndex = 0;
int rightSortedIndex = sortedNums.length - 1;
while(leftSortedIndex < rightSortedIndex) {
int sum = sortedNums[leftSortedIndex] + sortedNums[rightSortedIndex];
if(sum == target) {
break;
} else if(sum < target) {
leftSortedIndex++;
} else {
rightSortedIndex--;
}
}
int leftIndex = -1;
int rightIndex = -1;
for(int index=0; index < nums.length; index++) {
if(leftIndex == -1 && nums[index] == sortedNums[leftSortedIndex]) {
leftIndex = index;
continue;
}
if(rightIndex == -1 && nums[index] == sortedNums[rightSortedIndex]) {
rightIndex = index;
}
}
return (new int[] {leftIndex, rightIndex});
}
}

class Solution {
public int[] twoSum(int[] nums, int target) {
int[] sortedNums = Arrays.copyOf(nums, nums.length);
Arrays.sort(sortedNums);
int leftSortedIndex = 0;
int rightSortedIndex = sortedNums.length - 1;
while(leftSortedIndex < rightSortedIndex) {
int sum = sortedNums[leftSortedIndex] + sortedNums[rightSortedIndex];
if(sum == target) {
break;
} else if(sum < target) {
leftSortedIndex++;
} else {
rightSortedIndex--;
}
}
int leftIndex = -1;
int rightIndex = -1;
for(int index=0; index < nums.length; index++) {
if(leftIndex == -1 && nums[index] == sortedNums[leftSortedIndex]) {
leftIndex = index;
} else if(rightIndex == -1 && nums[index] == sortedNums[rightSortedIndex]) {
rightIndex = index;
}
}
return (new int[] {leftIndex, rightIndex});
}
}

If anyone want for C this might help...It is brute forced not with hashtable!
#include <stdio.h>
int main(int argc, char const *argv[])
{
int i,j,l,target,m,n;
printf("Enter how many elements you want :\n");
scanf("%d",&i);
int array[i];
printf("Input elements\n" );
for (j=0;j<i;j++)
scanf("%d",&array[j]);
printf("[");
for (l=0;l<i;l++)
printf(" %d ",array[l] );
printf("]\n");
printf("Input the target :");
scanf("%d",&target);
for (m=0;m<i;m++)
{
for (n=m+1;n<i;n++)
{
if ((array[m]+array[n])==target)
{
printf("Their indices is \n[%d,%d]",m,n);
}
}
}
return 0;
}

Related

Solving a LeetCode problem to find first and last index of target in array in O(log n)

I have solved a leet code question. The question asks:
Given an array of integers nums sorted in non-decreasing order, find the starting and ending position of a given target value.
If target is not found in the array, return [-1, -1].
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
Example 3:
Input: nums = [], target = 0
Output: [-1,-1]
Constraints:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums is a non-decreasing array.
-109 <= target <= 109
This is my solution (using binary search), but I am not actually sure if this is O(log n) since the runtime of my answer is 6 ms.
public static int[] returnIndices = new int[2];
public int[] searchRange(int[] nums, int target) {
int[] resultArr = new int[2];
if(nums.length == 0 && target == 0) {
resultArr[0] = -1;
resultArr[1] = -1;
System.out.print(resultArr[0] + "," + resultArr[1]);
return resultArr;
}
binarySearch(nums, target);
resultArr = getIndexOf();
System.out.print(resultArr[0] + "," + resultArr[1]);
return resultArr;
}
public int[] getIndexOf() {
return returnIndices;
}
public int[] setIndex(int index) {
if(index == -1) {
returnIndices[0] = -1;
returnIndices[1] = -1;
}
else {
int lastIndex = index + 1;
returnIndices[0] = index;
returnIndices[1] = lastIndex;
}
return returnIndices;
}
public int binarySearch(int[] nums, int target) {
int low = 0;
int high = nums.length;
int mid = 0;
while(low <= high) {
mid = low+high/2;
if(nums[mid] == target) {
setIndex(mid);
return mid;
}
if(nums[mid] < target) {
low = mid+1;
}
if(nums[mid] > target) {
high = mid-1;
}
}
setIndex(-1);
return -1;
}
My submission takes 0 ms, yours actually returns wrong result. The idea is that array is non-decreasing but contains duplicates, but despite of duplicates you still may use binary search: you just need to promote index found to the left and to the right using binary search again but with other boundaries.
while(low <= high) {
// that is not correct
// must be either (low + high)/2
// or (low + high) >>> 2
mid = low+high/2;
if(nums[mid] == target) {
setIndex(mid);
// here you should not return
// you need to save mid, and
// depending on what boundary
// you are looking promote it
// either to the left or to the right
return mid;
}
if(nums[mid] < target) {
low = mid+1;
}
if(nums[mid] > target) {
high = mid-1;
}
}

Codility PermCheck Solution isn't working on a few data sets

Trying to solve codility lessons for practice and working on this.
Written my code in Java and tested the code on a wide range of inputs, however the code fails for extreme_min_max, single and double in the codility test results.
Assumption given:
N is an integer within the range [1..100,000].
Each element of array A is an integer within the range [1..1,000,000,000].
Explanation of my code:
1. Sort the given array.
2. Iterate over each element in the array to find the difference between every consecutive pair. If the difference is not 1, Then its not a perm hence return 0. In case there is only one element in the array, return 1.
Can anyone please help me find out the bug(s) in my code?
My code:
public int solution(int[] A)
{
if(A.length == 1)
return 1;
Arrays.sort(A);
for (int i = 0; i < A.length-1; i++)
{
long diff = Math.abs(A[i] - A[i+1]);
if(diff!=1)
return 0;
}
return 1;
}
Here is simple and better implementation which runs in O(N) time complexity and takes O(N) space complexity.
public int solution(int[] A)
{
int size = A.length;
int hashArray[] = new int[size+1];
for (int i = 0; i < size; i++)
{
if(A[i]>size)
return 0;
else
hashArray[A[i]]+=1;
}
for(int i=1;i<=size;i++)
if(hashArray[i]!=1)
return 0;
return 1;
}
Try this in C# (Score 100%) :
using System;
using System.Linq;
class Solution {
public int solution(int[] A) {
if (A.Any(x => x == 0)) { return 0; }
var orderSelect = A.OrderBy(x => x).GroupBy(x => x);
if (orderSelect.Any(x => x.Count() > 1)) { return 0; }
var res = Enumerable.Range(1, A.Length).Except(A);
return res.Any() ? 0 : 1;
}
}
Pretty simple:
Your code doesn't check this condition:
A permutation is a sequence containing each element from 1 to N once, and only once.
Ensure that the first element after sorting is 1, and everything should work.
I'm not big on Java syntax, but what you want to do here is:
Create an array temp the length of A - initialized to 0.
Go over A and do temp[A[i]]++.
Go over temp, and if any place in the array is not 1, return false.
If duplicate exists - return 0 I have implemented with 100% pass
https://codility.com/demo/results/trainingWX2E92-ASF/
public static int permCheck(int A[]){
Set<Integer> bucket = new HashSet<Integer>();
int max = 0;
int sum=0;
for(int counter=0; counter<A.length; counter++){
if(max<A[counter]) max=A[counter];
if(bucket.add(A[counter])){
sum=sum+A[counter];
}
else{
return 0;
}
}
System.out.println(max+"->"+sum);
int expectedSum = (max*(max+1))/2;
if(expectedSum==sum)return 1;
return 0;
}
Here's my first 100% code.
I can't say if it's the fastest but it seems all correct -- watch the double OR ( || ) condition.
import java.util.Arrays;
class Solution
{
public int solution(int[] A)
{
int i = 0;
int size = A.length;
if ( size > 0 && size < 100001)
{
// Sort the array ascending:
Arrays.sort(A);
// Check each element:
for(i = 0; i < size; i++)
if ( A[i] > size || A[i] != (i + 1) )
return 0;
return 1;
}
return 0;
}
}
EDIT
Actually, we need not worry about valid first element data (i.e. A[i] > 0) because, after sorting, a valid perm array must have A[0] = 1 and this is already covered by the condition A[i] = i + 1.
The upper limit for array entries (> 1,000,000,000) is restricted further by the limit on the array size itself (100,000) and we must check for conformity here as there will be a Codility test for this. So I have removed the lower limit condition on array entries.
Below code runs and gave me a 100%, the time complexity is O(n):
private static int solution(int[] A) {
int isPermutation = 1; // all permutations start at 1
int n = A.length;
Arrays.sort(A);
if (n == 0) return 0; // takes care of edge case where an empty array is passed
for (int i = 0; i < n; i++) {
if (A[i] != isPermutation) { //if current array item is not equals to permutation, return 0;
return 0;
}
isPermutation++;
}
return 1;
}
100% score with complexity O(N)
public int solution(int[] A) {
int res = 1;
if (A.length == 1 && A[0]!=1)
return 0;
int[] B = new int[A.length];
for (int j : A) {
int p = j - 1;
if (A.length > p)
B[p] = j;
}
for (int i = 0; i < B.length - 1; i++) {
if (B[i] + 1 != B[i + 1]) {
res = 0;
break;
}
}
return res;
}

Given an array of integers, find out the third largest value in the array

public int thirdLargest(int[] arr){
int f_l = arr[0];
int s_l = arr[0];
int t_l = arr[0];
for(int i=1;i<arr.length;i++)
{
if (f_l < arr[i]){
t_l = s_l;
s_l = f_l;
f_l = arr[i];
}
else if (s_l < arr[i]){
t_l = s_l;
s_l = arr[i];
}
else if (t_l < arr[i]){
t_l = arr[i];
}
}
return t_l;
}
my code didn't passes some cases,any suggestion?
parameter {24,27,30,31,34,37,40,42}' , passes
parameter {2,-1,-2,-3,-4,-5}' , fails
This is simply cause by the fact that you initialize all values to arr[0]. If all elements are smaller than arr[0] this code won't update the values, even though the second-largest element for example wouldn't be arr[0]. Instead initialize the variables for the third/second/largest value with Integer.MIN_VALUE and start the search with the first element (index = 0) instead of the second.
There is actually a well-known algorithm for this, which is more generic than yours. It is called quick-select and looks like a quick sort with an optimization making it faster (linear time in average) : since we don't need to sort the array, we just recurse on the part of the array containing the index we are looking for (in your case, third item so index 2).
Here is an implementation in Java :
private static final Random rd = new Random();
public static int kthElement(int[] arr, int k) {
return kthElement(arr,k,0,arr.length);
}
private static T kthElement(int[] arr, int k, int min, int max) {
if (min < max - 1) {
int p = pivot(arr,min,max);
return p == k - 1 ? arr[p] :
p < k - 1 ? kthElement(arr,k,p + 1,max) : kthElement(arr,k,min,p);
}
return arr[min];
}
private static int pivot(int[] arr, int min, int max) {
int pivot = min + rd.nextInt(max - min);
swap(arr,pivot,max - 1);
pivot = min;
for (int i=min ; i<max ; i++)
if (arr[i] < arr[max - 1]) swap(arr,i,pivot++);
swap(arr,max - 1,pivot);
return pivot;
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
Well, as an alternative to your working code, here is a solution that will allow you to find the Nth largest integer in your array using Collections to do the heavy lifting:
import java.util.Arrays;
import java.util.Collections;
public class ArrayNthLargest {
public static int getNthLargest(int[] arrayInput, int n) {
Integer[] sortedArray = new Integer[arrayInput.length];
for (int i = 0; i < arrayInput.length; i++) {
sortedArray[i] = new Integer(arrayInput[i]);
}
Arrays.sort(sortedArray, Collections.reverseOrder());
return (sortedArray[n - 1]);
}
public static void main(String[] args){
int nth = new Integer(0);
int n = new Integer(3);
int[] testArray = {1,2,3,4,5,6,23,44,55,8,1};
nth = getNthLargest(testArray, n);
System.out.printf("The %d sorted array value is %d", n, nth);
}
}
This was actually an interesting question to me to do in O(n) complexity. I hope this solution is order n. I used an ArrayList as a stack (since Stack object won't allow addition of items in specific incidences (I've generalized it).
public int thirdLargest(int[] arr){
public int N_TH = 3; // Assuming this is nth largest you want
public ArrayList<Integer> largest = new ArrayList<Integer>(N_TH);
for(int i = 0;i<N_TH;i++)
largest.add(0); // initialize the ArrayList
for(int i = 0;i<arr.length;i++) {
for(int j=0;j<largest.size();j++){
if(arr[i] >= largest.get(j)) {
// Add the item at the correct index
// Pop the last element
largest.remove(largest.size()-1);
largest.add(j,arr[i]);
break;
}
}
}
return largest.get(N_TH);
}
Let me know if you find any problems with it, I might have mistyped part of trying to put it in OP's method.
EDIT won't work with negative numbers at the moment. You can find the smallest value in arr and initialize largest with that value. Then it'll also with negative numbers

issues with codingbat maxMirror exercise

So basically, I've been going through these codingBat problems, and when I get really stuck, I usually check out the solution and trace the logic and that has helped me not get stuck on later problems which used similar ideas.
This max mirror problem is not like the others for me personally; I have no idea how to actually write the code to solve it, even forming the algorithm is kind of tricky for me
We'll say that a "mirror" section in an array is a group of contiguous elements such that somewhere in the array, the same group appears in reverse order. For example, the largest mirror section in {1, 2, 3, 8, 9, 3, 2, 1} is length 3 (the {1, 2, 3} part). Return the size of the largest mirror section found in the given array.
maxMirror({1, 2, 3, 8, 9, 3, 2, 1}) → 3
maxMirror({1, 2, 1, 4}) → 3
maxMirror({7, 1, 2, 9, 7, 2, 1}) → 2
Now, in terms of the algorithm, I sort of want to say something like, if we start by checking if the whole array is a mirror and then decrease the checked area size by 1 if it's not. But in terms of the pseudocode and the real code I have no idea.
My go to solution in cases like this where what your code should be doing is always doing it manually, then figuring out the essence of how it is that I am tackling the solution.
For this problem I found myself looking at possible subsets of the original array, then looking backwards through the original array to see if I can find that same subset again.
Next, I translated that into pseudocode,
for each segment in nums
check if nums contains segment backwards
Repeated, but this time with more implementation details worked out.
for each segment in nums, starting with the largest
reverse the segment
check if nums contains reversed segment
if it does, return the size of that segment
Next, find some likely candidates for methods in the pseudocode and write them. I chose to do this for "reverse" and "contains":
private int[] reverse(int[] nums) {
int[] rtn = new int[nums.length];
for (int pos = 0; pos < nums.length; pos++) {
rtn[nums.length - pos - 1] = nums[pos];
}
return rtn;
}
private boolean contains(int[] nums, int[] segment) {
for (int i = 0; i <= nums.length - segment.length; i++) {
boolean matches = true;
for (int j = 0; j < segment.length; j++) {
if (nums[i + j] != segment[j]) {
matches = false;
break;
}
}
if (matches) return true;
}
return false;
}
Finally, implement the rest:
public int maxMirror(int[] nums) {
for (int window = nums.length; window > 0; window--) {
for (int pos = 0; pos <= nums.length - window; pos++) {
int[] segment = new int[window];
for (int innerpos = 0; innerpos < window; innerpos++) {
segment[innerpos] = nums[pos + innerpos];
}
segment = reverse(segment);
if (contains(nums, segment)) {
return window;
}
}
}
return 0;
}
My irrelevant two cents....
public int maxMirror(int[] nums) {
// maximum mirror length found so far
int maxlen= 0;
// iterate through all possible mirror start indexes
for (int front = 0; front < nums.length; front++) {
// iterate through all possible mirror end indexes
for (int back = nums.length - 1; back >= front; back--) {
// this inner for-loop determines the mirror length given a fixed
// start and end index
int matchlen = 0;
Boolean match = (nums[front] == nums[back]);
// while there is a match
// 1. increment matchlen
// 2. keep on checking the proceeding indexes
while (match) {
matchlen++;
int front_index = front + matchlen;
int back_index = back - matchlen;
// A match requires
// 1. Thee indexes are in bounds
// 2. The values in num at the specified indexes are equal
match =
(front_index < nums.length) &&
(back_index >= 0) &&
(nums[front_index] == nums[back_index]);
}
// Replace the max mirror length with the new max if needed
if (matchlen > maxlen) maxlen = matchlen;
}
}
return maxlen;
}
Alternative solution designed to confuse you
public int maxMirror(int[] nums) {
return maxlen_all_f(nums, 0);
}
int maxlen_all_f(int [] nums, int f) {
return (f >= nums.length)
? 0
: max(
maxlen_for_start_f(nums, f, nums.length - 1),
maxlen_all_f(nums, f + 1)
);
}
int max(int a, int b){
return (a > b)
? a
: b;
}
int maxlen_for_start_f(int [] nums, int f, int b) {
return (b < f)
? 0
: max(
matchlen_f(nums, f, b),
maxlen_for_start_f(nums, f, b - 1)
);
}
int matchlen_f(int[] nums, int f, int b) {
return match_f(nums, f, b)
? 1 + matchlen_f(nums, f + 1, b - 1)
: 0;
}
Boolean match_f(int [] nums, int a, int b) {
return (a < nums.length && b >= 0) && (nums[a] == nums[b]);
}
The solution is simple rather than making it complex:
public static int maxMirror(int[] nums) {
final int len=nums.length;
int max=0;
if(len==0)
return max;
for(int i=0;i<len;i++)
{
int counter=0;
for(int j=(len-1);j>i;j--)
{
if(nums[i+counter]!=nums[j])
{
break;
}
counter++;
}
max=Math.max(max, counter);
}
if(max==1)
max=0;
return max;
}
This is definitely not the best solution in terms of performance. Any further improvements are invited.
public int maxMirror(int[] nums) {
int maxMirror=0;
for(int i=0;i<nums.length;i++)
{
int mirror=0;
int index=lastIndexOf(nums,nums[i]);
if(index!=-1){
mirror++;
for(int j=i+1;j<nums.length;j++)
{
if(index>=0&&existsInReverse(nums,index,nums[j]))
{
mirror++;
index--;
continue;
}
else
break;
}
if(mirror>maxMirror)
maxMirror=mirror;
}
}
return maxMirror;
}
int lastIndexOf(int[] nums,int num){
for(int i=nums.length-1;i>=0;i--)
{
if(nums[i]==num)
return i;
}
return -1;
}
boolean existsInReverse(int nums[],int startIndex,int num){
if(startIndex!=0&&(nums[startIndex-1]==num))
return true;
return false;
}
Here is my answer , Hope the comments explain it well :)
public int maxMirror(int[] nums) {
int max = 0;
// our largest mirror section found stored in max
//iterating array
for(int i=0;i<nums.length;i++){
int iterator = i; // iterator pointing at one element of array
int counter = 0;//counter to count the mirror elements
//Looping through for the iterator element
for(int j=nums.length-1;j>=i;j--){
//found match i.e mirror element
if(nums[iterator] == nums[j]){
iterator++; // match them until the match ends
counter++; // counting the matched ones
}
else{
//matching ended
if(counter >= max){//checking if previous count was lower than we got now
max = counter; // store the count of matched elements
}
counter = 0; // reset the counter
iterator = i; // reset the iterator for matching again
}
}
if(counter >= max){//checking if previous count was lower than we got now
max = counter;// store the count of matched elements at end of iteration
}
}
return max;//return count
}

Implementing a binary insertion sort using binary search in Java

I'm having trouble combining these two algorithms together. I've been asked to modify Binary Search to return the index that an element should be inserted into an array. I've been then asked to implement a Binary Insertion Sort that uses my Binary Search to sort an array of randomly generated ints.
My Binary Search works the way it's supposed to, returning the correct index whenever I test it alone. I wrote out Binary Insertion Sort to get a feel for how it works, and got that to work as well. As soon as I combine the two together, it breaks. I know I'm implementing them incorrectly together, but I'm not sure where my problem lays.
Here's what I've got:
public class Assignment3
{
public static void main(String[] args)
{
int[] binary = { 1, 7, 4, 9, 10, 2, 6, 12, 3, 8, 5 };
ModifiedBinaryInsertionSort(binary);
}
static int ModifiedBinarySearch(int[] theArray, int theElement)
{
int leftIndex = 0;
int rightIndex = theArray.length - 1;
int middleIndex = 0;
while(leftIndex <= rightIndex)
{
middleIndex = (leftIndex + rightIndex) / 2;
if (theElement == theArray[middleIndex])
return middleIndex;
else if (theElement < theArray[middleIndex])
rightIndex = middleIndex - 1;
else
leftIndex = middleIndex + 1;
}
return middleIndex - 1;
}
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int i = 0;
int[] returnArray = new int[theArray.length + 1];
for(i = 0; i < theArray.length; i++)
{
returnArray[ModifiedBinarySearch(theArray, theArray[i])] = theArray[i];
}
for(i = 0; i < theArray.length; i++)
{
System.out.print(returnArray[i] + " ");
}
}
}
The return value I get for this when I run it is 1 0 0 0 0 2 0 0 3 5 12. Any suggestions?
UPDATE: updated ModifiedBinaryInsertionSort
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int index = 0;
int element = 0;
int[] returnArray = new int[theArray.length];
for (int i = 1; i < theArray.lenght - 1; i++)
{
element = theArray[i];
index = ModifiedBinarySearch(theArray, 0, i, element);
returnArray[i] = element;
while (index >= 0 && theArray[index] > element)
{
theArray[index + 1] = theArray[index];
index = index - 1;
}
returnArray[index + 1] = element;
}
}
Here is my method to sort an array of integers using binary search.
It modifies the array that is passed as argument.
public static void binaryInsertionSort(int[] a) {
if (a.length < 2)
return;
for (int i = 1; i < a.length; i++) {
int lowIndex = 0;
int highIndex = i;
int b = a[i];
//while loop for binary search
while(lowIndex < highIndex) {
int middle = lowIndex + (highIndex - lowIndex)/2; //avoid int overflow
if (b >= a[middle]) {
lowIndex = middle+1;
}
else {
highIndex = middle;
}
}
//replace elements of array
System.arraycopy(a, lowIndex, a, lowIndex+1, i-lowIndex);
a[lowIndex] = b;
}
}
How an insertion sort works is, it creates a new empty array B and, for each element in the unsorted array A, it binary searches into the section of B that has been built so far (From left to right), shifts all elements to the right of the location in B it choose one right and inserts the element in. So you are building up an at-all-times sorted array in B until it is the full size of B and contains everything in A.
Two things:
One, the binary search should be able to take an int startOfArray and an int endOfArray, and it will only binary search between those two points. This allows you to make it consider only the part of array B that is actually the sorted array.
Two, before inserting, you must move all elements one to the right before inserting into the gap you've made.
I realize this is old, but the answer to the question is that, perhaps a little unintuitively, "Middleindex - 1" will not be your insertion index in all cases.
If you run through a few cases on paper the problem should become apparent.
I have an extension method that solves this problem. To apply it to your situation, you would iterate through the existing list, inserting into an empty starting list.
public static void BinaryInsert<TItem, TKey>(this IList<TItem> list, TItem item, Func<TItem, TKey> sortfFunc)
where TKey : IComparable
{
if (list == null)
throw new ArgumentNullException("list");
int min = 0;
int max = list.Count - 1;
int index = 0;
TKey insertKey = sortfFunc(item);
while (min <= max)
{
index = (max + min) >> 1;
TItem value = list[index];
TKey compKey = sortfFunc(value);
int result = compKey.CompareTo(insertKey);
if (result == 0)
break;
if (result > 0)
max = index - 1;
else
min = index + 1;
}
if (index <= 0)
index = 0;
else if (index >= list.Count)
index = list.Count;
else
if (sortfFunc(list[index]).CompareTo(insertKey) < 0)
++index;
list.Insert(index, item);
}
Dude, I think you have some serious problem with your code. Unfortunately, you are missing the fruit (logic) of this algorithm. Your divine goal here is to get the index first, insertion is a cake walk, but index needs some sweat. Please don't see this algorithm unless you gave your best and desperate for it. Never give up, you already know the logic, your goal is to find it in you. Please let me know for any mistakes, discrepancies etc. Happy coding!!
public class Insertion {
private int[] a;
int n;
int c;
public Insertion()
{
a = new int[10];
n=0;
}
int find(int key)
{
int lowerbound = 0;
int upperbound = n-1;
while(true)
{
c = (lowerbound + upperbound)/2;
if(n==0)
return 0;
if(lowerbound>=upperbound)
{
if(a[c]<key)
return c++;
else
return c;
}
if(a[c]>key && a[c-1]<key)
return c;
else if (a[c]<key && a[c+1]>key)
return c++;
else
{
if(a[c]>key)
upperbound = c-1;
else
lowerbound = c+1;
}
}
}
void insert(int key)
{
find(key);
for(int k=n;k>c;k--)
{
a[k]=a[k-1];
}
a[c]=key;
n++;
}
void display()
{
for(int i=0;i<10;i++)
{
System.out.println(a[i]);
}
}
public static void main(String[] args)
{
Insertion i=new Insertion();
i.insert(56);
i.insert(1);
i.insert(78);
i.insert(3);
i.insert(4);
i.insert(200);
i.insert(6);
i.insert(7);
i.insert(1000);
i.insert(9);
i.display();
}
}

Categories

Resources