Dynamic programming: transformation of one string into another - algorithm

We have two strings a and b. We need to transform string a into b.
Transformation rule
Capitalize zero or more of a's lowercase letters at some index i (i.e., make them uppercase).
Delete all of the remaining lowercase letters in a.
eg.
a = daBcd
b = ABC
Capitalize a and c and remove d from string a. So we can transform a into b.
(I found this problem on HackerRank)
So I wrote java code as below:
static boolean abbreviation(String a, String b, int i, int j, Map<String, Boolean> memo) {
if(j==b.length()){
if(i==a.length())
return true;
return !a.substring(i, a.length()).matches("\\D*[A-Z]+\\D*");
}
if(i==a.length())
return false;
String key = i+"-"+j;
if(memo.containsKey(key))
return memo.get(key);
if(a.substring(i).equalsIgnoreCase(b.substring(j))){
memo.put(key, true);
return true;
}
if(Character.isUpperCase(a.charAt(i))){
if(a.charAt(i)==b.charAt(j)){
memo.put(key, abbreviation(a, b, i+1, j+1, memo));
return memo.get(key);
}
else{
memo.put(key, false);
return false;
}
}
if(abbreviation(a, b, i+1, j, memo)){
memo.put(key, true);
return true;
}
else if(Character.toUpperCase(a.charAt(i))==b.charAt(j)){
memo.put(key, abbreviation(a, b, i+1, j+1, memo));
return memo.get(key);
}
else{
memo.put(key, false);
return false;
}
}
It is working fine but giving timeout for large test cases. I used hashmap for memoization but still it was giving timeout. So I looked into the editor solution, it is something like this:
static boolean abbreviationOptimal(String a, String b){
char[] s = a.toCharArray();
char[] t = b.toCharArray();
int n = s.length;
int m = t.length;
//created memoization table for dynamic programming
boolean[][] dp = new boolean[n+1][m+1];
dp[0][0] = true;
//Cannot understand logic behind this--
for(int i = 0;i <= n;i++){
for(int j = 0;j <= m;j++){
//what are these conditions here (all three if)
if(i < n && s[i] >= 'a' && s[i] <= 'z'){
//why |= operator here
dp[i+1][j] |= dp[i][j];
}
if(i < n && j < m && s[i] == t[j]){
dp[i+1][j+1] |= dp[i][j];
}
if(i < n && j < m && s[i]+'A'-'a' == t[j]){
dp[i+1][j+1] |= dp[i][j];
}
}
}
return dp[n][m];
}
I have no idea, what is happening in this function. Required some clear explanation on this.

In the solution dp has boolean value which indicates if it's possible to reach to position where i characters have been matched from a and j characters from b. If we have reached state dp[i][j] then we can:
Delete ith character from a if it is lowercase in order to reach dp[i + 1][j]
Match ith character from a with jth character from b in order to reach dp[i + 1][j + 1]
If we can reach state dp[a.length()][b.length()] then transformation can be done. Here's a bit shorter example with couple of comments, hope it helps:
static String abbreviation(String a, String b) {
// Complete this function
char[] x = a.toCharArray();
char[] y = b.toCharArray();
boolean[][] dp = new boolean[x.length + 1][y.length + 1];
// 0 consumed from a, 0 consumed from b is reachable position
dp[0][0] = true;
for (int i = 0; i < x.length; i++) {
for (int j = 0; j <= y.length; j++) {
// Delete lowercase char from a
if (Character.isLowerCase(x[i])) {
dp[i + 1][j] |= dp[i][j];
}
// Match characters, make sure char from a is upper case
if (j < y.length && Character.toUpperCase(x[i]) == y[j]) {
dp[i + 1][j + 1] |= dp[i][j];
}
}
}
return dp[x.length][y.length] ? "YES" : "NO";
}

Related

Print entire path of Maximum cost in a maze from first cell to last cell when moving right and bottom is allowed

I need a help in a enhancement to very popular dynamic programming question. Min/Max cost path
Question : There is a 2D matrix which has values (0,1,-1).
0 -> no cherry. can go here
1 -> cherry present. can go here
-1 -> thorn present. can't go here
we need to print maximum cherrys collected and entire path in which we can collect maximum cherrys.
input :
{{0, 1, -1}, {1, 0, -1},{1,1,1}};
output :
4
(0,0) -> (1,0) -> (2,0) -> (2,1) -> (2,2)
I can write the code to print the maximum cherrys collected but not able to get the logic to how to store the entire path. Since we decide which cell to be choosen while backtracking, it appears little tough. didnt find any web help in this regard. I'm stuck, Any help would be appreciated.
public int cherryPickup(int[][] grid) {
if (grid.length == 0) {
return -1;
}
int[][] dp = new int[grid.length][grid[0].length];
setDp(dp);
int forwardMax = getForwardMax(grid, dp, 0, 0);
return forwardMax;
}
private void setDp(int[][] dp) {
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
dp[i][j] = -1;
}
}
}
private int getForwardMax(int[][] grid, int[][] dp, int i, int j) {
if(dp[i][j] != -1) {
return dp[i][j];
}
if (grid[i][j] == -1) {
dp[i][j] = 0;
return dp[i][j];
}
if (i == grid.length - 1 && j == grid[0].length - 1) {
dp[i][j] = grid[i][j];
return dp[i][j];
}
if (i == grid.length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i, j + 1);
return dp[i][j];
}
if (j == grid[0].length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i + 1, j);
return dp[i][j];
}
dp[i][j] = grid[i][j] + Math.max(getForwardMax(grid, dp, i + 1, j), getForwardMax(grid, dp, i, j + 1));
return dp[i][j];
}
As per suggestion in the comment for having the path[][] and storing the index which is maximum.
Below code stores (1,1) also 1, which is incorrect.
private int getForwardMax(int[][] grid, int[][] dp, int i, int j, int[][] path) {
if(dp[i][j] != -1) {
return dp[i][j];
}
if (grid[i][j] == -1) {
dp[i][j] = 0;
return dp[i][j];
}
if (i == grid.length - 1 && j == grid[0].length - 1) {
dp[i][j] = grid[i][j];
return dp[i][j];
}
if (i == grid.length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i, j + 1, path);
path[i][j] =1;
return dp[i][j];
}
if (j == grid[0].length - 1) {
dp[i][j] = grid[i][j] + getForwardMax(grid, dp, i + 1, j, path);
path[i][j] =1;
return dp[i][j];
}
int left = getForwardMax(grid, dp, i + 1, j, path);
int right = getForwardMax(grid, dp, i, j + 1, path);
int max = Math.max(left, right);
if(max == left) {
path[i+1][j] = 1;
} else {
path[i][j+1] = 1;
}
dp[i][j] = grid[i][j] + max;
return dp[i][j];
}
Well if you write your dynamic programming top down (as you did), restoring actual answer is actually very easy.
So you have a function getForwardMax which for given cell, return maximum amount we can collect moving right or down
You also know starting position, so all you need to do is build the answer step by step:
Let's say you're in some cell (r,c)
if there is only one possible move (you're at border) just do it
otherwise we can either move to (r+1,c) or (r,c+1)
we also know how much we will earn by moving to those cells and completing our path to the goal from getForwardMax function
So we just pick move that gives better result
Ok, bottom up DP is a correct solution as yours. I just realized you won't need separate path[][] to store the path and iterate over them.
You can use a simple while loop and choose the best among the 2 options of right and down.
If both happen to have same values, you need not worry as one grid could have multiple correct solutions. So, choosing either one in case of clash will still give you a correct solution.
We start from (0,0).
If value contained in dp[x][y+1] cell at the right + current grid[x][y] gives us the value same as dp[x][y], we move right, else we move down.
Snippet:
int x = 0,y = 0;
while(x != rows-1 || y != cols-1){
System.out.println("( " + x + " , " + y + " )");
if(x+1 < rows && grid[x][y] + dp[x+1][y] == dp[x][y]){
x++;
}else if(y + 1 < cols && grid[x][y] + dp[x][y+1] == dp[x][y]){
y++;
}
}
System.out.println("( " + x + " , " + y + " )");
Full Code: https://ideone.com/lRZ6E5

Find zeroes to be flipped so that number of consecutive 1’s is maximized

Find zeroes to be flipped so that number of consecutive 1’s is maximized.
Input: arr[] = {1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1}
m = 2
Output: 5 7
We are allowed to flip maximum 2 zeroes. If we flip
arr[5] and arr[7], we get 8 consecutive 1's which is
maximum possible under given constraints .
Now if we were to find just the maximum number of 1's that is possible, is it possible to solve using dynamic programming approach?
This problem can be solved in linear time O(N) and linear space O(N). Its not full fledged dynamic programming, but its similar to that as it uses precomputation.
Data Structures Used:
1.left: It is an integer array, of same length as given array. It is precomputed such that for every position i:
left[i] = Number of consecutive 1's to the left position i
2.right: It is an integer array, of same length as given array. It is precomputed such that for every position i:
right[i] = Number of consecutive 1's to the right position i
These can be computed in single traversal of the array.Assuming arr is the original array, following pseudocode does the job:
Pseudocode for populating left array
left()
{
int count = 0;
for(int i = 0;i < arr length; ++i)
{
if(i == 0)
{
left[i] = 0;
if(arr[i] == 1)
count++;
continue;
}
else
{
left[i] = count;
if(arr[i] == 1)
count++;
else count = 0;
}
}
}
Pseudocode for populating right array
right()
{
int count = 0;
for(int i = arr length - 1;i >= 0; --i)
{
if(i == arr length - 1)
{
right[i] = 0;
if(arr[i] == 1)
count++;
continue;
}
else
{
right[i] = count;
if(arr[i] == 1)
count++;
else count = 0;
}
}
}
Now the only thing we have to do is :check all pair of positions i and j (i < j) such that arr[i] = 0 and arr[j] = 0 and for no position between i and j arr[i] should be 0 and Keep track of the pair for which we get maximum value of the following:
left[i] + right[j] + right[l]
You could also use left[i] + right[j] + left[r].
left[i] tells the number of consecutive 1's to the left of position i and right[j] tells the number of consecutive 1's to the right of position j and the number of consecutive 1's between i and j can be counted be left[r] OR right[l], and therefore, we have two candidate expressions.
This can also be done in single traversal, using following pseudocode:
max_One()
{
max = 0;
l = -1, r = -1;
for(int i = 0;i < arr length; ++i)
{
if(arr[i] == 0)
{
if(l == -1)
l = i;
else
{
r = i;
if(left[l] + right[r] + right[l] > max)
{
max = left[l] + right[r] + right[l];
left_pos = l;
right_pos = r;
}
l = r;
}
}
}
}
You should use sliding window concept here - use start and end vars to store index of range. Whenever you encounter a 0, increment the counter of zeros received. Include it in current length.. If zeros encounter equals m+1, increment start till you encounter 0.
public static int[] zerosToFlip(int[] input, int m) {
if (m == 0) return new int[0];
int[] indices = new int[m];
int beginIndex = 0;
int endIndex = 0;
int maxBeginIndex=0;
int maxEndIndex=0;
int zerosIncluded = input[0] == 0 ? 1 : 0;
for (int i = 1; i < input.length; i++) {
if (input[i] == 0) {
if (zerosIncluded == m) {
if (endIndex - beginIndex > maxEndIndex - maxBeginIndex){
maxBeginIndex = beginIndex;
maxEndIndex = endIndex;
}
while (input[beginIndex] != 0) beginIndex++;
beginIndex++;
} else {
zerosIncluded++;
}
}
endIndex++;
}
if (endIndex - beginIndex > maxEndIndex - maxBeginIndex){
maxBeginIndex = beginIndex;
maxEndIndex = endIndex;
}
int j = 0;
for (int i = maxBeginIndex; i <= maxEndIndex; i++) {
if (input[i] == 0) {
indices[j] = i;
++j;
}
}
return indices;
}

How to generate n^r variations of an array (i.e. variations with repetition of nCk)

my question is based from topcoder's recent SRM (628 500 point question), i'm trying to solve the string parsing question by brute force since the number of solutions cannot exceed 5^5 and I'm very close. My question is how would I go about generating not only n! permutations but n^r permutations in c#. Using an adaptation of Knuth's lexicographical permutation algorithm my solution works but not for cases when the answer (the winning permutation) has repeated characters.
input example: "X{}]X{X{}]X]"
public string ifPossible(string expression)
{
char[] c = new char[6] { '(', ')', '{', '}', '[', ']' };
StringBuilder sb = new StringBuilder(expression);
int j = 0;
special(sb);
while (my_next_permutation(c) && sb.ToString().Contains('X'))
{
for(int i = 0; i < sb.Length;i++)
{
if (sb[i] == 'X')
sb[i] = c[j++];
}
special(sb);
if (sb.Length > 0)
{
sb.Clear();
sb.Append(expression);
special(sb);
j = 0;
}
else
{
break;
}
}
if (sb.Length > 0)
return "impossible";
return "possible";
}
void special(StringBuilder sb)
{
while (sb.ToString().Contains("()") || sb.ToString().Contains("[]") || sb.ToString().Contains("{}"))
{
while (sb.ToString().Contains("()"))
sb.Replace("()", "");
while (sb.ToString().Contains("[]"))
sb.Replace("[]", "");
while (sb.ToString().Contains("{}"))
sb.Replace("{}", "");
}
}
public Boolean my_next_permutation(char[] a)
{
int N = a.Length, i = N - 2;
for (; i >= 0; i--)
if (a[i] < a[i + 1])
break;
if (i < 0) return false;
for (int j = N - 1; j >= i; j--)
{
if (a[j] > a[i])
{
var temp = a[i];
a[i] = a[j];
a[j] = temp;
break;
}
}
for (int j = i + 1; j < (N + i + 1) / 2; j++)
{
var temp = a[j];
a[j] = a[N + i - j];
a[N + i - j] = temp;
}
return true;
}
I could have used the array idea as gmch and jrh suggested but I
ended up using this:
IEnumerable<string> GetPermutations(char[] list, int? resultSize = null, bool withRepetition = false)
{
List<string> l = new List<string>();
char[] result = new char[resultSize.HasValue ? resultSize.Value : list.Length];
var indices = new int[result.Length];
for (int i = 0; i < indices.Length; i++)
indices[i] = withRepetition ? -1 : indices.Length - i - 2;
int curIndex = 0;
while (curIndex != -1)
{
indices[curIndex]++;
if (indices[curIndex] == list.Length)
{
indices[curIndex] = withRepetition ? -1 : curIndex - 1;
curIndex--;
}
else
{
result[curIndex] = list[indices[curIndex]];
if (curIndex < indices.Length - 1)
curIndex++;
else
yield return new string(result);
}
}
}
I got the idea from this page http://noldorin.com/programming/CombinatoricsUtilities.cs.txt
All credit given to Alex Regueiro.

Distinct Subsequences DP explanation

From LeetCode
Given a string S and a string T, count the number of distinct
subsequences of T in S.
A subsequence of a string is a new string which is formed from the
original string by deleting some (can be none) of the characters
without disturbing the relative positions of the remaining characters.
(ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).
Here is an example: S = "rabbbit", T = "rabbit"
Return 3.
I see a very good DP solution, however, I have hard time to understand it, anybody can explain how this dp works?
int numDistinct(string S, string T) {
vector<int> f(T.size()+1);
//set the last size to 1.
f[T.size()]=1;
for(int i=S.size()-1; i>=0; --i){
for(int j=0; j<T.size(); ++j){
f[j]+=(S[i]==T[j])*f[j+1];
printf("%d\t", f[j] );
}
cout<<"\n";
}
return f[0];
}
First, try to solve the problem yourself to come up with a naive implementation:
Let's say that S.length = m and T.length = n. Let's write S{i} for the substring of S starting at i. For example, if S = "abcde", S{0} = "abcde", S{4} = "e", and S{5} = "". We use a similar definition for T.
Let N[i][j] be the distinct subsequences for S{i} and T{j}. We are interested in N[0][0] (because those are both full strings).
There are two easy cases: N[i][n] for any i and N[m][j] for j<n. How many subsequences are there for "" in some string S? Exactly 1. How many for some T in ""? Only 0.
Now, given some arbitrary i and j, we need to find a recursive formula. There are two cases.
If S[i] != T[j], we know that N[i][j] = N[i+1][j] (I hope you can verify this for yourself, I aim to explain the cryptic algorithm above in detail, not this naive version).
If S[i] = T[j], we have a choice. We can either 'match' these characters and go on with the next characters of both S and T, or we can ignore the match (as in the case that S[i] != T[j]). Since we have both choices, we need to add the counts there: N[i][j] = N[i+1][j] + N[i+1][j+1].
In order to find N[0][0] using dynamic programming, we need to fill the N table. We first need to set the boundary of the table:
N[m][j] = 0, for 0 <= j < n
N[i][n] = 1, for 0 <= i <= m
Because of the dependencies in the recursive relation, we can fill the rest of the table looping i backwards and j forwards:
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
N[i][j] = N[i+1][j] + N[i+1][j+1];
} else {
N[i][j] = N[i+1][j];
}
}
}
We can now use the most important trick of the algorithm: we can use a 1-dimensional array f, with the invariant in the outer loop: f = N[i+1]; This is possible because of the way the table is filled. If we apply this to my algorithm, this gives:
f[j] = 0, for 0 <= j < n
f[n] = 1
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
f[j] = f[j] + f[j+1];
} else {
f[j] = f[j];
}
}
}
We're almost at the algorithm you gave. First of all, we don't need to initialize f[j] = 0. Second, we don't need assignments of the type f[j] = f[j].
Since this is C++ code, we can rewrite the snippet
if (S[i] == T[j]) {
f[j] += f[j+1];
}
to
f[j] += (S[i] == T[j]) * f[j+1];
and that's all. This yields the algorithm:
f[n] = 1
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
f[j] += (S[i] == T[j]) * f[j+1];
}
}
I think the answer is wonderful, but something may be not correct.
I think we should iterate backwards over i and j. Then we change to array N to array f, we looping j forwards for not overlapping the result last got.
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
N[i][j] = N[i+1][j] + N[i+1][j+1];
} else {
N[i][j] = N[i+1][j];
}
}
}

Check if an array element is a sum of two earlier elements using recursion

I was solving practice questions from a book when I stumbled upon this one :
*Describe a recursive algorithm that will check if an array A of
integers contains an integer A[i] that is the sum of two integers
that appear earlier in A, that is, such that
A[i] = A[j] +A[k] for j,k < i.
*
I have been thinking about this for a few hours but haven't been able to come up with a good recursive algorithm.
A recursive solution without any loops (pseudocode):
bool check (A, i, j, k)
if (A[j] + A[k] == A[i])
return true
else
if (k + 1 < j) return check (A, i, j, k + 1)
else if (j + 1 < i) return check (A, i, j + 1, 0)
else if (i + 1 < A.size) return check (A, i + 1, 1, 0)
else return false
The recursive function is called with check(A, 2, 1, 0). To highlight the main part of the algorithm it does not check if the array initially has more than two elements.
Not very efficient but..
search(A, j, k) {
for (int i = 0; i < A.length; i++) {
if (A[i] == A[j] + A[k]) {
return i;
}
}
if (k + 1 == A.length) {
if (j + 1 < A.length) {
return search(A, j + 1, 0);
}
return -1; // not found
}
return search (A, j, k + 1);
}
Start the search with
search(A, 0, 0);
In python. The first function (search is less efficient O(n3)), but it also gives the j and k, the second one is more efficient (O(n2)), but only returns i.
def search(A, i):
for j in xrange(i):
for k in xrange(i):
if A[i] == (A[j] + A[k]):
return i, j, k
if i > 0:
return search(A, i - 1)
def search2(A, i, sums):
if A[i] in sums:
return i
if i == len(A) - 1:
return None
for j in range(i + 1):
sums.add(A[i] + A[j])
return search2(A, i + 1, sums)
if __name__ == '__main__':
print search([1, 4, 3], 2)
print search([1, 3, 4], 2)
print search2([1, 4, 3], 0, set())
print search2([1, 3, 4], 0, set())
It will print:
None
(2, 0, 1)
None
2
/**
* Describe a recursive algorithm that will check if an array A of integers contains
* an integer A[i] that is the sum of two integers that appear earlier in A,
* that is, such that A[i] = A[j]+A[k] for j,k < i.
* #param A - array
* #param i - initial starting index (0)
* #param j - initival value for j (0)
* #param k - initial value for k (0)
* #param n - length of A - 1
* #return - true if combination of previous 2 elements , false otherwise
*/
public boolean checkIfPreviousTwo(int[] A, int i, int j, int k, int n){
if(i >= n) return false;
if(j < i && k < i){
if(A[j] + A[k] == A[i]) return true;
return(
checkIfPreviousTwo(A, i, j + 1, k, n) ||
checkIfPreviousTwo(A, i, j, k + 1, n)
);
}
return checkIfPreviousTwo(A, i + 1, j, k, n);
}
This algorithm should be fairly efficient (well, O(n2)):
import Data.Set (Set, empty, fromList, member, union)
-- Helper function (which does all the work)
hassum' :: (Ord a, Num a) => Set a -> [a] -> [a] -> Bool
-- Parameters:
-- 1. All known sums upto the current element
-- 2. The already handles elements
-- 3. The not yet checked elements
-- If there are no elements left to check, there is no sum
hassum' _ _ [] = False
-- Otherwise...
hassum' sums done (x:xs)
-- Check if the next element is a known sum
| x `member` sums = True
-- Otherwise calculate new possible sums and check the remaining elements
| otherwise = hassum' sums' done' xs
where sums' = sums `union` fromList [x+d | d <- done]
done' = x:done
-- Main function
hassum :: (Ord a, Num a) => [a] -> Bool
hassum as = hassum' empty [] as
I hope you can make sense of it even if you might not know Haskell.
The Java version, it also return the index of i,j,k.
the running time of the worst case is O(N^2)
=1= using recursion
private static void findSum(Object[] nums, long k, int[] ids/* indexes*/) {
// walk from both sides towards center
int l = ids[0];
int r = ids[1];
if (l == r) {
ids[0] = -1;
ids[1] = -1;
return;
}
int sum = (Integer) nums[l] + (Integer) nums[r];
if (sum == k) {
return;
}
if (sum < k) {
ids[0]++;
} else {
ids[1]--;
}
findSum(nums, k, ids);
}
private static int binarySearchPositionIndexOf(List<Integer> list, int l, int r, int k) {
int m = (l + r) / 2;
if (m == l) { // end recursion
return r;
}
int mv = list.get(m);
if (mv == k) {
return m;
}
if (mv < k) {
return binarySearchPositionIndexOf(list, m, r, k);
}
return binarySearchPositionIndexOf(list, l, m, k);
}
private static void check(List<Integer> data, List<Integer> shadow, int i, int[] ids) {
if (i == data.size()) {
ids[0] = -1;
ids[1] = -1;
return;
}
// sort it in
int indexAfterSort = -1;
int v = data.get(i);
if (v >= data.get(i - 1)) {
indexAfterSort = i;
} else if (v <= data.get(0)) {
indexAfterSort = 0;
} else if (data.size() == 3) {
indexAfterSort = i - 1;
} else {
indexAfterSort = binarySearchPositionIndexOf(data, 0, i - 1, data.get(i));
}
if (indexAfterSort != i) {
data.add(indexAfterSort, data.remove(i));
shadow.add(indexAfterSort, shadow.remove(i));
}
// find sum
if (indexAfterSort >= 2) {
List<Integer> next = data.subList(0, indexAfterSort); //[)
ids[0] = 0;
ids[1] = next.size() - 1;
findSum(next.toArray(), data.get(indexAfterSort), ids);
}
// recursion
if (ids[0] == -1 && ids[1] == -1) {
check(data, shadow, i + 1, ids);
return;
}
ids[0] = shadow.get(ids[0]);
ids[1] = shadow.get(ids[1]);
ids[2] = i;
}
public static int[] check(final int[] array) {
List shadow = new LinkedList() {{
for (int i = 0; i < array.length; i++) {
add(i);
}
}};
if (array[0] > array[1]) {
array[0] ^= array[1];
array[1] ^= array[0];
array[0] ^= array[1];
shadow.add(0, shadow.remove(1));
}
int[] resultIndex = new int[3];
resultIndex[0] = -1;
resultIndex[1] = -1;
check(new LinkedList<Integer>() {{
for (int i = 0; i < array.length; i++) {
add(array[i]);
}
}}, shadow, 2, resultIndex);
return resultIndex;
}
Test
#Test(timeout = 10L, expected = Test.None.class)
public void test() {
int[] array = new int[]{4, 10, 15, 2, 7, 1, 20, 25};
int[] backup = array.clone();
int[] result = check(array);
Assert.assertEquals(backup[result[2]], 25);
Assert.assertEquals(result[2], 7);
Assert.assertEquals(backup[result[0]], 10);
Assert.assertEquals(result[0], 1);
Assert.assertEquals(backup[result[1]], 15);
Assert.assertEquals(result[1], 2);
array = new int[]{4, 10, 15, 2, 7, 1, 10, 125};
backup = array.clone();
result = check(array);
Assert.assertEquals(result[0], -1);
Assert.assertEquals(result[1], -1);
}
=2= simple one without recurison:
// running time n + n^2
// O(n^2)
public static int[] check2(final int[] array) {
int[] r = new int[3];
r[0] = -1;
r[1] = -1;
r[2] = -1;
Map<Integer, List<Integer>> map = new HashMap(array.length);
for (int i = 0; i < array.length; i++) {
int v = array[i];
List<Integer> ids = map.get(v);
if (ids == null) {
ids = new LinkedList();
}
ids.add(i);
map.put(v, ids);
}
for (int k = 0; k < array.length; k++) {
int K = array[k];
for (int j = 0; j < array.length; j++) {
int I = K - array[j];
if (map.keySet().contains(I)) {
List<Integer> ids = map.get(I);
for (int i : ids) {
if (i != j) {
r[0] = j;
r[1] = i;
r[2] = k;
return r;
}
}
}
}
}
return r;
}
Test:
int[] array = new int[]{0,8,8};
int[] result = check2(array);
Assert.assertEquals(array[result[2]], 8);
Assert.assertEquals(result[2], 1);
Assert.assertEquals(array[result[0]], 0);
Assert.assertEquals(result[0], 0);
Assert.assertEquals(array[result[1]], 8);
Assert.assertEquals(result[1], 1);

Resources