Find an element in a list/array (a big list) - java

I'm actually doing an easy CodinGame --> I have to find if an element exists in a list.
I've tested a first solution, it was working but it wasn't really optimized (according to the machine).
So I've tried another solution but :
When I test my code for this 2nd solution, it returns the right answers but when I'm submitting my code, it tells me that my solution is completely wrong (it doesn't work if the list is empty, and also if the list is huge, ...).
Please can you help me ?
Here is my first naive solution :
public static boolean check(int[] ints, int k) {
boolean res = false;
for(int i : ints){
if(i == k){
res = true;
break;
}
}
return res;
}
Here is the code of my 2nd solution that is supposed to be optimized:
static boolean exists(int [] ints, int k){
boolean res = false;
int first = 0;
int last = ints.length;
int mid = (first + last)/2;
while(first <= last){
if( ints[mid] < k){
first = mid +1;
}else if (ints[mid] == k){
res = true;
break;
}else{
last = mid -1;
}
mid = (first + last)/2;
}
if(first > last){
res = false;
}
return res;
}

Finally I've found the solution to my problem !!!!!
Here it is :
import java.util.Arrays;
class A{
static boolean exists(int[] ints, int k){
boolean res = false;
int index = Arrays.binarySearch(ints, k);
if (index<0){
res = false;
}else{
res = true;
}
return res;
}
}

I suppose you are trying to implement Binary search in the second solution.
If so, please check this answer. Your input array must be sorted in non-decreasing order, because Binary Search works only with sorted input data. For example, you can simply type Arrays.sort(arr); and then pass your array into exists() method. But the overall time&space complexities will be O(n log n).
Fixed some bugs in your implementation:
public static boolean exists(int[] ints, int k) {
int first = 0;
int last = ints.length - 1;
while (first <= last) {
int mid = first + (last - first) / 2; // to avoid integer overflow in extremely large arrays
if (ints[mid] < k) {
first = mid + 1;
} else if (ints[mid] == k) {
return true;
} else {
last = mid - 1;
}
}
return false;
}

Related

Logic Error: Binary search fails with more than two elements in a string array

The objective is to return the index of an element in a string array if present. The method uses a basic binary search using compareTo statements. With more than two elements in a tested array, the method will not detect the present element and return -1. The Java code this question is referring to is below. How do I make the binary search method work as intended?
public static int binarySearch(String[] array, String x) {
int high = array.length - 1;
int low = 0;
while (low <= high) {
int mid = low + (high - low) / 2;
if (x.compareTo(array[mid]) == 0) {
return mid;
}
if (x.compareTo(array[mid]) > 0) {
low = mid + 1;
}
else {
high = mid - 1;
}
}
return -1;
}
add an extra variable and set it to -1;
int loc=-1;
change the code
int mid=low+(high-low)/2;
to
int mid=(low+high)/2;
if(x.compareTo(array[mid]==0)
{
loc=mid;
break;
}
else if(x<array[mid])
{
last=mid-1;
}
else
{
low=mid+1;
}
then
if(loc>=0)
{
System.out.println(loc+1);
}
else
{
System.out.println("no element");
}

find nth prime in java with low time complexity

I'm trying to find a low time complexity solution for finding nth prime.
However there's some method problems I'm quite confused.
Also I want to know is mine has a low time complexity or can it be better?
I've tried two different ways to find the prime while the first one is way too slow, so i changed another one. But the boolean method has some problem which i have no idea.
public static int FInd_NthPrime(int n){
int num=0,j,c=2;
while (true) {
if(isPrime(c)){
num = num+1;
}
c = c+1;
break;
}
return c; // the error happened
}
public static boolean isPrime(int n) {
for (int i = 2; i < Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
public static void print_nth_prime(int num){
int result = FInd_NthPrime(num);
System.out.print(num +" "+result);
}
I expect anyone tell me the mistake in boolean method and is there any better way to make low time complexity for finding the nth prime。
You only have to test odd integers and special case "2".
And when doing the isPrime test, just do the modulo check against existing primes already discovered.
public static int FInd_NthPrime(int n){
int val = 3; // first odd number greater than 2
int result = 0;
if (n <= 1) {
return 2; // special case for 2, the only even prime
}
// build up a Hash table of all discovered primes so far
ArrayList<Integer> primes = new ArrayList<Integer>();
primes.add(2);
while (n > 1) {
if (isPrime(val, primes)) {
n--;
result = val;
}
val += 2; // increment to the next odd integer
}
return result;
}
public static boolean isPrime(int n, ArrayList<Integer> primes) {
if (n == 2) {
return true;
}
int stop = (int)Math.sqrt(n);
for (int divisor : primes) {
if ((n % divisor) == 0) {
return false;
}
if (divisor > stop) {
break;
}
}
//System.out.format("Added %d to prime list\n", n);
primes.add(n);
return true;
}

Implementing binary search on an array of Strings

I'm having a bit of trouble with this. The input array is based on file input and the size of the array is specified by the first line in the file. The binarySearch method seems to look alright but it doesn't seem to be working would. Anybody be able to help? Thanks.
public static int binarySearch(String[] a, String x) {
int low = 0;
int high = a.length - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (a[mid].compareTo(x) < 0) {
low = mid + 1;
} else if (a[mid].compareTo(x) > 0) {
high = mid - 1;
} else {
return mid;
}
}
return -1;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter the name of your file (including file extension): ");
String filename = input.next();
String[] numArray;
try (Scanner in = new Scanner(new File(filename))) {
int count = in.nextInt();
numArray = new String[count];
for (int i = 0; in.hasNextInt() && count != -1 && i < count; i++) {
numArray[i] = in.nextLine();
}
for (int i = 0; i < count; i++) //printing all the elements
{
System.out.println(numArray[i]);
}
String searchItem = "The";
System.out.println("The position of the String is:");
binarySearch(numArray, searchItem);
} catch (final FileNotFoundException e) {
System.out.println("That file was not found. Program terminating...");
e.printStackTrace();
}
}
I have added following example for your further referance.
import java.util.Arrays;
public class BinaryStringSearch {
public static void main(String[] args) {
String array[] ={"EWRSFSFSFSB","BB","AA","SDFSFJ","WRTG","FF","ERF","FED","TGH"};
String search = "BB";
Arrays.sort(array);
int searchIndex = binarySearch(array,search);
System.out.println(searchIndex != -1 ? array[searchIndex]+ " - Index is "+searchIndex : "Not found");
}
public static int binarySearch(String[] a, String x) {
int low = 0;
int high = a.length - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (a[mid].compareTo(x) < 0) {
low = mid + 1;
} else if (a[mid].compareTo(x) > 0) {
high = mid - 1;
} else {
return mid;
}
}
return -1;
}
}
I hope it will help:
public static void main(String ar[]){
String str[] = {"account","angel","apple","application","black"};
String search= "application";
int length = str.length-1;
BinarySearchInString findStrin = new BinarySearchInString();
int i = findStrin.find(str, 0, length, search);
System.out.println(i);
}
public int find(String first[], int start, int end, String searchString){
int mid = start + (end-start)/2;
if(first[mid].compareTo(searchString)==0){
return mid;
}
if(first[mid].compareTo(searchString)> 0){
return find(first, start, mid-1, searchString);
}else if(first[mid].compareTo(searchString)< 0){
return find(first, mid+1, end, searchString);
}
return -1;
}
As spotted by #Mike Rylander you forgot to output the result.
You should use Arrays.binarySearch instead of your own implementation.
(As a general rule, JRE libraries are well-tested, well-documented and fast. I googled "java binary search" and this question is well-ranked. I had a try with #Thusitha Indunil's code, which didn't appear to work. I googled harder and found Arrays.binarySearch, which worked.)
I believe that your problem is that you forgot to output the results. Try replacing binarySearch(numArray, searchItem); with System.out.println(binarySearch(numArray, searchItem));
There are four issues that I can spot in addition to the already mentioned missing print of the result.
1: You have a String[] called numArray and you are searching for a String, "The" the name numArray is possibly a bit mis-leading.
2: I assume you have some sort of specified input file format where the number of String in the file are specified by an integer as the first token in the file. This is ok however, as a condition in the for loop that populates the numArray there is in.hasNextInt(), and the next token is taken out of the Scanner using in.nextLine(). You should use complementing check/removal methods such as in.hasNext() with in.next(). Check out the Scanner API.
3: The binarySearch(String[], String) method uses String.compareTo(String). This is determines a lexicographical ordering of this String to the parameter String. Trying to compare upper case to lower case may not yield what you expect, as "the".compareTo("The") will not result in 0. You should check out the String API for options to either force all of your input to one case, maybe while reading the file, or use a different flavor of a compare to method.
4: The last thing that I see may be considered a bit of a corner case, however with a sufficiently large String array, and a search string that may reside far in the right side, ie. high index side, of the array you may get an ArrayIndexOutOfBoundsException. This is because (low + high) can result in a negative value, when the result "should" be greater than Integer.MAX_VALUE. Then the result is divided by two and still yields a negative value. This can be solved by bit shifting the result instead of dividing by 2, (low + high) >>> 1. Joshua Bloch has a great article about this common flaw in divide and conquer algorithms.
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable midVal = (Comparable) a[mid];
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid;
}
return -(low + 1);
}

Sum of List<Integer> recursively

Hello fellow programmers.
I am having a very silly problem.. I'm supposed to sum all the integers in a List, recursively. I know that there is an easier way to do this, and I actually made that method too (see class below). But the meaning of this assignment is that I have to split the list up into 2 halves and then calculate the sum recursively on both halves, and last I just return half1 + half2.
The problem is that the advanced method does not return the sum of all values. Can anyone please help me?
The method sum is the simple method. Summer(Summarize in danish) is the more advanced method.
package opgave1;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class BinærSøgning {
public static void main(String[] args) {
Random random = new Random();
int tal = 3;
List<Integer> liste = new ArrayList<Integer>();
for (int i = 0; i < 10; i++)
liste.add(random.nextInt(10));
Collections.sort(liste);
System.out.println(liste);
// System.out.println(binærSøgning(liste, 0, tal));
System.out.println(summer(liste, 0));
}
public static int binærSøgning(List<Integer> liste, int start, int find) {
if (liste.size() > 0) {
int midt = liste.size() / 2;
if (liste.get(midt) == find)
return start + midt;
else if (liste.size() > 1) {
if (find < liste.get(midt))
return binærSøgning(liste.subList(0, midt), start, find);
else
return binærSøgning(liste.subList(midt + 1, liste.size()), start + midt + 1, find);
}
}
return -1;
}
public static int sum (List<Integer> list, int i)
{
if (i == list.size())
return 0;
else
return list.get(i) + sum(list, i+1);
}
public static int summer(List<Integer> list, int start){
int right = 0;
int left = 0;
if(start == list.size()){
return 0;
} else {
int mid = list.size() / 2;
if(start < mid){
left += list.get(start) + summer(list.subList(0, mid), start+1);
} else if(mid < list.size()){
right += list.get(mid) + summer(list.subList(mid+1, list.size()), mid+1);
}
}
return right + left;
}
}
Ii's much easier with two base cases, there is no need for an extra 'start' parameter if you use sublists. (Because it's homework, I won't fill in the details.)
public static int summer(List<Integer> list) {
//base 1
if (list.size() == 0) {
}
//base 2
else if (list.size() == 1) {
}
else
{
//no need for if statements now!
int left = summer(list.sublist(/* */))
int right = summer(list.sublist(/* */))
return left + right;
}
}
Are you sure that you have to split the list? Usually, when you get this task for homework, the meaning is something like:
public static int sum(List<Integer> l,int start) {
if (start==l.size()) return 0;
return l.get(start)+sum(l,start+1);
}
You are missing out elements of list when you are sending start+1 in the recursion.
left += list.get(start) + summer(list.subList(0, mid), start+1);
You should rather send
left += list.get(0) + summer(list.subList(1, mid), 0);
and
right += list.get(mid) + summer(list.subList(mid+1, list.size()), 0);
I dont see the need to sending any start value. Every recursion should take the 0 in place of start.
I think it can be solved in a simpler way, by keeping track of both the first and last index of the range, like this:
public static int sum(List<Integer> list, int i, int j) {
if (i == j)
return list.get(i);
int half = (i + j) / 2;
return sum(list, i, half) + sum(list, half + 1, j);
}
It's called like this:
List<Integer> list = Arrays.asList(1, 2, 3);
System.out.println(sum(list, 0, list.size()-1));
It will work fine for non-empty lists. If the list is empty, you'll need to check it before calling sum.
First of all, you don't need to cut the list in half if all you need to do is use recursion. The sum of the elements of a list is the sum of its first element + the sum of all the elements of the rest of the list.
Second, your method is too complex. The sum of the elements of the list is 0 if the list is empty, the unique element is it contains 1 element, and the sum of the results of the method applied to the two sublists if it contains more than 1. You don't need any start argument.
This should get you started.
EDIT: since Oscar Lopez gave you the answer, but I find it too complex, here's mine:
public static int sum(List<Integer> list) {
if (list.isEmpty()) {
return 0;
}
else if (list.size() == 1) {
return list.get(0);
}
else {
int half = list.size() / 2;
return sum(list.subList(0, half)) + sum(list.subList(half, list.size()));
}
}
I am wondering a reason of getting a "half" of the List.The solution for the question is the one and only:
public int sum_list(List<Integer> list) {
if (list == null || list.isEmpty()) {
return 0;
}
return list.remove(0) + sum_list(list);
}
import java.util.*;
public class SumListByRecursion {
public static int sumByRec(List<Integer> list) {
int size = list.size();
if(size > 0) {
return list.get(0) + sumByRec(list.subList(1, size));
}
return 0;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println("List:"+" "+list);
int sum = sumByRec(list);
System.out.println("Sum of the list:"+" "+sum);
}
}
You can use this method for sum all ement of given list.
public static Integer sumOfList(List<Integer> list){
try {
return list.get(0) + sumOfList(list.subList(1, list.size()));
}catch (Exception e) {
return 0;
}
}

A recursive algorithm to find two integers in an array that sums to a given integer

I need an algorithm to determine if an array contains two elements that sum to a given integer.
The array is sorted.
The algorithm should be recursive and runs in O(n).
The recursive step should be based on the sum, meaning the method passes the sum and return true or false depending on the end result (if two elements are found - return true, else - return false)
Only linear data structures can be used.
Any ideas are appreciated..
You can convert any iterative algorithm into a recursive one by using (for instance) tail recursion. I'd be more expansive, if it weren't homework. I think you'll understand it from the other post.
Normally I'd use a Map, but since one of the requirements is to use a linear data structure, I think that's excluded, so I'd go about using a boolean array.
public boolean hasSum( int[] numbers, int target )
{
boolean[] hits = new boolean[ target + 1 ];
return hasSumRecursive( 0, numbers, target, hits );
}
public boolean hasSumRecursive( int index, int[] numbers, int target, boolean[] hits )
{
...
}
Hopefully this is a good enough hint.
I think hash is ok, for example, 1,3,7,9,12,14,33...
if we want sum=21, we hash the numbers into a hash table, So, O(n).
we iterator them, when we get 7, we let 21-7=14, so we hash 14, we can find it. so 7+14=21,
we got it!
Here is a solution witch takes into account duplicate entries. It is written in javascript and assumes array is sorted. The solution runs in O(n) time and does not use any extra memory aside from variable.
var count_pairs = function(_arr,x) {
if(!x) x = 0;
var pairs = 0;
var i = 0;
var k = _arr.length-1;
if((k+1)<2) return pairs;
var halfX = x/2;
while(i<k) {
var curK = _arr[k];
var curI = _arr[i];
var pairsThisLoop = 0;
if(curK+curI==x) {
// if midpoint and equal find combinations
if(curK==curI) {
var comb = 1;
while(--k>=i) pairs+=(comb++);
break;
}
// count pair and k duplicates
pairsThisLoop++;
while(_arr[--k]==curK) pairsThisLoop++;
// add k side pairs to running total for every i side pair found
pairs+=pairsThisLoop;
while(_arr[++i]==curI) pairs+=pairsThisLoop;
} else {
// if we are at a mid point
if(curK==curI) break;
var distK = Math.abs(halfX-curK);
var distI = Math.abs(halfX-curI);
if(distI > distK) while(_arr[++i]==curI);
else while(_arr[--k]==curK);
}
}
return pairs;
}
I solved this during an interview for a large corporation. They took it but not me.
So here it is for everyone.
Start at both side of the array and slowly work your way inwards making sure to count duplicates if they exist.
It only counts pairs but can be reworked to
use recursion
find the pairs
find pairs < x
find pairs > x
Enjoy!
It is pretty easy. It is important for array to be sorted.
Correct algorithm with O(n) time complexity and no additional space is:
public static boolean isContainsSum(int[] arr, int sum) {
for (int i = 0, j = arr.length - 1; i < j; ) {
if (arr[i] + arr[j] == sum)
return true;
if (arr[i] + arr[j] < sum)
i++;
else
j--;
}
return false;
}
To make it recursive, you need just replace i and j iterations with recursive call:
public static boolean isContainsSumRecursive(int[] arr, int sum) {
return isContainsSumRecursive(arr, sum, 0, arr.length - 1);
}
private static boolean isContainsSumRecursive(int[] arr, int sum, int i, int j) {
if (i == j)
return false;
if (arr[i] + arr[j] == sum)
return true;
if (arr[i] + arr[j] < sum)
return isContainsSumRecursive(arr, sum, i + 1, j);
return isContainsSumRecursive(arr, sum, i, j - 1);
}
Here is my solution: I iterate until the first number is greater than the expected sum, then until to second one or the sum of two is greater than the expected sum. If I do not want a correct answer, I return {-1,-1} (assuming all numbers are positive integers)
{
private static int[] sumOfTwo(int[] input, int k) {
for (int i = 0; i < input.length - 1; i++) {
int first = input[i];
for (int j = 1; j < input.length; j++) {
int second = input[j];
int sum = first + second;
if (sum == k) {
int[] result = {first, second};
return result;
}
if (second > k || sum > k) {
break;
}
}
if (first > k) {
break;
}
}
int[] begin = {-1, -1};
return begin;
}
}
Here is the recursion method to perform the groupSum
public boolean groupSum(int start, int[] nums, int target)
{
if (start >= nums.length) {
return (target == 0);
}
return groupSum(start + 1, nums, target - nums[start]) || groupSum(start +
1,nums,target)
}
def ExistsSum(A, i, j, Target):
if i >= j:
return False # Failure, all candidate pairs exhausted
if A[i] + A[j] < Target:
return ExistsSum(A, i+1, j, Target) # Try a larger sum
if A[i] + A[j] > Target:
return ExistsSum(A, i, j-1, Target) # Try a smaller sum
return True # Success
Run with
ExistsSum(A, 0, len(A)-1, Target)
bool solve(vector<int> &sorted_array, int l, int r, int target) {
if(l>=r) {
return false;
}
if(sorted_array[l] + sorted_array[r] == target) {
return true;
}
if(sorted_array[l] + sorted_array[r] > target) {
return solve(sorted_array, l, r-1, target);
}
if(sorted_array[l] + sorted_array[r] < target) {
return solve(sorted_array, l+1, r, target);
}
}
int main() {
vector<int> a = ...
solve(a, 0, a.size() - 1, target)
}
Here is my solution using recursion
pair<int,int> twoSum(int arr[], int s, int e, int target, pair<int, int>p){
//base case
if(arr[s] + arr[e] == target){
// pair<int,int>p;
p.first = arr[s];
p.second = arr[e];
return p;
}
while(s < e-1){
if(arr[s] + arr[e] < target){
s++;
return twoSum(arr, s, e, target, p);
}
if(arr[s] + arr[e] > target){
e--;
return twoSum(arr, s, e, target, p);
}
}
//if there is no pair possible
cout<<"pair is not possible" <<endl;
return p;
}
Sort the array. Search for the complement of each number (sum-number). Complexity O(nlogn).

Categories