I have an array int x[] and a number. I like to do search on the array such that x[i] + x[i+1] = number.
What is the most efficient and fastest way in Java?
Here is a pseudo code, this should work. Only n memory reads.
buff1 = x[0]
buff2 = 0
for i = 1 to n - 1
buff2 = x[i]
if (buff1 + buff2) == number
then
MATCH
endif
buff1 = buff2
endfor
If the array is unsorted and your only doing a few searches use phoxis' method. It's expected to run in O(n*k), where n is the size of x, and k is the number of searches you wan't to make.
If the array is sorted, we know that x[i]<=number/2 and x[i+1]>=number/2. Use binary search to find the (last) predecessor to number/2+1, and check if the match.
int i = binaryPredecessor(x , number/2 + 1);
if(x[i] + x[i+1] == number){
return i;
}
else if(x[i-1] + x[i] == number){
//The case where x[i] == number/2, and we found the last of two occurrences
return i-1;
} else {
//No match exists
return -1;
}
The runtime is O(log(n)*k).
If you do a lot of searches, it might be worth while to sort the array, and use the above method. The array can be sorted in O(n*log(n)) [see mergersort]. So if you want to do more log(n) searches, it's worth to sort the array. (If k is close to log(n), do some testing, to see whats best :) )
Related
I'm new at algorithms and want to know how to solve this task. A detailed Java solution is desirable.
You have been given an integer nā„2 and an integer array A[0..nā1] which is sorted in
nondecreasing order . All numbers repeat 1 time but one number repeats 2 times, how do you find the number that repeat 2 times. Using data structures and built-in functions was not allowed. Complexity of algorithm should be O(lg(n))
You can use a custom binary search algorithm.
We can observe that if there would be only values that repeated once (which occur twice), then the size of the array is even, and we have for each even index i: A[i] == A[i+1].
Since there is exactly one triplet, the array's size is odd, and so if we find an even index i for which A[i] == A[i+1] we know that the triplet did not occur at the left side of i. If however A[i] != A[i+1], then we are sure the triplet occurred at the left side of i.
This is all we need to perform a binary search. We should just make sure we always make our checks at even indices.
Here is an implementation in JavaScript:
function binarySearchTriplet(arr) {
let lo = 0, hi = arr.length - 1; // even
while (lo < hi) {
// Take mid, but force it to be even
mid = (lo + hi) >> 2 << 1;
if (arr[mid] === arr[mid+1]) {
lo = mid + 2;
} else {
hi = mid;
}
}
return arr[lo];
}
let arr = [1,1,4,4,4,5,5,7,7,2,2,6,6,8,8];
console.log(binarySearchTriplet(arr)); // 4
Ok so I currently have a String array which contains keycodes, and i want to check if the first element shares common specifications with the second , e.g. [012] has similar elements with [123]. I currently loop through the length of the first element, and then loop through the length of the second element, and compare those two like this:
If(A[1].charAt(j) == A[2].charAt[i]) c++; c is a counter to show how many
common elements the keycodes have. Here is the method i created
static boolean hasSimilarity(String[] A, int K, int i){
int c = 0;
for(int j = 0;j<K;j++){
for(int m = j;m<K;m++){
if(A[i].charAt(j) == A[i+1].charAt(m)) c++;
}
}
return c != 0;
}
And here is the execution of it in the Main class:
int max = -1;
findSimilar FS = new findSimilar();
for (int i = 0; i < sum.length -1; i++) {
boolean hasSimilar = FS.hasSimilarity(key,K,i);
if (!hasSimilar) {
int summ = sum[i] + sum[i + 1];
System.out.println(summ);
if (summ > max) {
max = summ;
}
}
}
When i run this, i get a java.lang.StringIndexOutOfBoundsException out of range: 0 . What am I doing wrong? Is there any better way to compare two keycodes in order to find similarities beetween them?
This error:
java.lang.StringIndexOutOfBoundsException out of range: 0
Can only occur if one of your strings is the blank string "".
You are attempting to get charAt(0) when there is no char 0 (ie first char).
āā-
You would avoid this problem, and have a far more efficient algorithm, if you first collected the counts of each character then compared those, which would have time complexity O(n), whereas your algorithm is O(n2) (albeit that it seems your n - the length of your inputs - is small).
Referencing https://www.geeksforgeeks.org/find-subarray-with-given-sum-in-array-of-integers/ for some reason I'm feeling a little thick about this and not totally grasping the reason that once you find the highest index for (current_sum - target_sum) in the map, that you know if you start at the index immediately following that in the array and include the values up to the current index where you encounter this in the array, that you have your subarray solution.
I pretty much get it, that it's because if we've reached a point in our iterating of the array that we've seen the difference between our current sum and the target number, then if we remove that difference from the sum we have found the subarray for the solution, but I can't quite grasp why exactly that is. For example, what if the difference is "2" but the index we have stored in our map where we last saw the sum was "2" is not immediately before the subarray leading up to where we are now and provides the solution. Again, I kind of get it but would appreciate a clear and precise explanation so I have that "aha" moment and more solidly grasp it.
Also wondering the logic that might lead me to this solution after solving this in a different way for positive integers only, namely the efficient solution covered here https://www.geeksforgeeks.org/find-subarray-with-given-sum/.
Thanks.
public static void subArraySum(int[] arr, int n, int sum) {
//cur_sum to keep track of cummulative sum till that point
int cur_sum = 0;
int start = 0;
int end = -1;
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < n; i++) {
cur_sum = cur_sum + arr[i];
//check whether cur_sum - sum = 0, if 0 it means
//the sub array is starting from index 0- so stop
if (cur_sum - sum == 0) {
start = 0;
end = i;
break;
}
//if hashMap already has the value, means we already
// have subarray with the sum - so stop
if (hashMap.containsKey(cur_sum - sum)) {
start = hashMap.get(cur_sum - sum) + 1;
end = i;
break;
}
//if value is not present then add to hashmap
hashMap.put(cur_sum, i);
}
// if end is -1 : means we have reached end without the sum
if (end == -1) {
System.out.println("No subarray with given sum exists");
} else {
System.out.println("Sum found between indexes "
+ start + " to " + end);
}
}
recently I met a question like this:
Assume you have an int N, and you also have an int[] and each element in this array can only be used once time. And we need to design an algorithm to get 1 to N by adding those numbers and finally return the least numbers we need to add.
For example:
N = 6, array is [1,3]
1 : we already have.
2 : we need to add it to the array.
3 : we can get it by doing 1 + 2.
4: 1 + 3.
5 : 2 + 3.
6 : 1 + 2 + 3.
So we just need to add 2 to our array and finally we return 1.
I am thinking of solving this by using DFS.
Do you have some better solutions? Thanks!
Here's an explanation for why the solution the OP posted works (the algorithm, briefly, is to traverse the sorted existing elements, keep an accumulating sum of the preceding existing elements and add an element to the array and sum if it does not exist and exceeds the current sum):
The loop tests in order each element that must be formed and sums the preceding elements. It alerts us if there is an element needed that's greater than the current sum. If you think about it, it's really simple! How could we make the element when we've already used all the preceding elements, which is what the sum represents!
In contrast, how do we know that all the intermediate elements will be able to be formed when the sum is larger than the current element? For example, consider n = 7, a = {}:
The function adds {1,2,4...}
So we are up to 4 and we know 1,2,3,4 are covered,
each can be formed from equal or lower numbers in the array.
At any point, m, in the traversal, we know for sure that
X0 + X1 ... + Xm make the largest number we can make, call it Y.
But we also know that we can make 1,2,3...Xm
Therefore, we can make Y-1, Y-2, Y-3...Y-Xm
(In this example: Xm = 4; Y = 1+2+4 = 7; Y-1 = 6; Y-2 = 5)
Q.E.D.
I don't know if this is a good solution or not:
I would create a second array (boolean array) remembering all numbers I can calculate.
Then I would write a method simulating the adding of a number to the array. (In your example the 1, 3 and 2 are added to the array).
The boolean array will be updated to always remember which values (numbers) can be calculated with the added numbers.
After calling the add method on the initial array values, you test for every Number x ( 1 <= x <= N ) if x can be calculated. If not call the add method for x.
since my explanation is no good I will add (untested) Java code:
static int[] arr = {3,5};
static int N = 20;
//An Array remembering which values can be calculated so far
static boolean[] canCalculate = new boolean[N];
//Calculate how many numbers must be added to the array ( Runtime O(N^2) )
public static int method(){
//Preperation (adding every given Number in the array)
for(int i=0; i<arr.length; i++){
addNumber(arr[i]);
}
//The number of elements added to the initial array
int result = 0;
//Adding (and counting) the missing numbers (Runtime O(N^2) )
for(int i=1; i<=N; i++){
if( !canCalculate[i-1] ){
addNumber(i);
result++;
}
}
return result;
}
//This Method is called whenever a new number is added to your array
//runtime O(N)
public static void addNumber( int number ){
System.out.println("Add Number: "+(number));
boolean[] newarray = new boolean[N];
newarray[number-1] = true;
//Test which values can be calculated after adding this number
//And update the array
for(int i=1; i<=N; i++){
if( canCalculate[i-1] ){
newarray[i-1] = true;
if( i + number <= N ){
newarray[i+number-1] = true;
}
}
}
canCalculate = newarray;
}
Edit: Tested the code and changed some errors (but rachel's solution seems to be better anyway)
It is a famous problem from dynamic programming. You can refer to complete solution here https://www.youtube.com/watch?v=s6FhG--P7z0
I just found a possible solution like this
public static int getNum(int n, int[] a) {
ArrayList<Integer> output = new ArrayList<Integer>();
Arrays.sort(a);
int sum = 0;
int i = 0;
while(true) {
if (i >= a.length || a[i] > sum + 1) {
output.add(sum + 1);
sum += sum + 1;
} else {
sum += a[i];
i++;
}
if (sum >= n) {
break;
}
}
return output.size();
};
And I test some cases and it looks correct.
But the one who write this didn't give us any hints and I am really confused with this one. Can anybody come up with some explanations ? Thanks!
This question already has answers here:
How to find all permutations of a given word in a given text?
(6 answers)
Closed 8 years ago.
This is not same as "How to check if a string contains s specific substring?" . I found a no of questions like that here but not precisely what i am looking for.
I am creating a program at a competitive coding site the problem of which states that we are given a string made of x,y,z and we have to count the number of substrings which contains atleast one of those chars but not all of them.I tried this...
String text = sc.next();
int l = text.length();
int count=0;
for(int j =1;j<=l;j++)
{
for(int i1 =0;i1<j;i1++){
String g = text.substring(i1,j);
if(g.contains("xyz")||g.contains("xzy")||g.contains("yzx")||g.contains("yxz")||g.contains("zxy")||g.contains("zyx"))
;
else
count++;
}
}
System.out.println(count);
And this worked(atleast for 2 test cases). But for the larger test cases my program is violating the time limit. Now i think that is because of the number of matching conditions in the if clause. I would like to know if there is any way by which i can just check if the substring contains 'xyz' in any order instead of checking for every order.Thanks! Any help is appreciated.
P.S- If anything else is responsible for the time limit violation, do mention out !
Here is a simple solution. Warning untested code!
String target = ...
String text = sc.next();
if (target.length() == 0) {
// matched!
} else {
for (int i = 0; i <= text.length() - target.length(); i++) {
if ((pos = target.indexOf(text.charAt(i))) >= 0) {
boolean[] found = new boolean[target.length()];
found[pos] = true;
int matchCount = 1;
outer: for (j = 1; j < target.length(); j++) {
pos = 0;
while (true) {
pos = target.indexOf(text.charAt(i + j), pos);
if (pos == -1) {
break outer;
} else if (!found[pos]) {
found[pos] = true;
matchCount++;
break;
}
}
}
if (matchCount == target.length()) {
// matched!
}
}
}
}
If you wanted to make this faster, one possibility is to clear and recycle the found array that we are using "mark off" the characters as we match them.
There may be more significant optimizations. However, I don't think that the Boyer-Moore "trick" of skipping a number of characters is going to work here.
UPDATE
Your original solution is O(N factorial(M)) where N is the text length, and M is the target string length.
My solution is O(N M).
The optimal solution involves calculating a running hash by multiplying prime numbers, as described in one of the answers to How to find all permutations of a given word in a given text?. I think it is O(N) on average.
(Hint: the solution I'm referring to as written looks like it is O(M N). However, we should be able to use the inverse multiplication equality:
((ab mod n) . (b-1 mod n)) mod n = a mod n
where a and b are the prime factors and n is 232 or 264 depending on whether we use int or long. Reference: wikipedia.
This will allow is to "multiply in" and then "inverse multiply out" the characters and therefore update the running hash in O(1) operations.)