Rotate Array

Rotate an array of n elements to the right by k steps.

For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].


同样是用三次翻转法。
Solution:

public class Solution {
    public void rotate(int[] nums, int k) {
        if (nums.length == 0) {
        	return;
        }
        k %= nums.length;
        sub(nums, nums.length - k, nums.length - 1);
        sub(nums, 0, nums.length - k - 1);
        sub(nums, 0, nums.length - 1);
    }

    private void sub(int[] nums, int start, int end) {
    	while (start < end) {
    		int tmp = nums[start];
    		nums[start] = nums[end];
    		nums[end] = tmp;
    		start++;
    		end--;
    	}
    }
}

3Sum closest

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

For example, given array S = {-1 2 1 -4}, and target = 1.

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).


public int threeSumClosest(int[] num, int target) {
    Arrays.sort(num);
    int result = num[0] + num[1] + num[2];
    for (int i = 0; i < num.length - 2; i++) {
        if (result == target) {
            return result;
        }
        int sum = sub(num, i+1, target - num[i]);
        if (Math.abs(target - sum - num[i]) < Math.abs(target - result)) {
            result = sum + num[i];
        }
    }
    return result;
}
private int sub(int[] num, int index, int target) {
    int start = index, end = num.length - 1;
    int result = num[index] + num[index+1];
    while (start < end) {
        int tmp = num[start] + num[end];
        if (Math.abs(target - tmp) < Math.abs(target - result)) {
            result = tmp;
        }
        if (num[start] + num[end] == target) {
            return target;
        }
        if (num[start] + num[end] < target) {
            start++;
        } else {
            end--;
        }
    }
    return result;
}

4sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:
Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
The solution set must not contain duplicate quadruplets.


Solution 1:递归解法超时,忘记了数组已经排好序,最里层2sum的时候直接用两个指针即可

public class Solution {
    public List<List<Integer>> fourSum(int[] num, int target) {
        Arrays.sort(num);
        List<List<Integer>> res = sub(num, target, 0, 4);
        return res == null ? new ArrayList<List<Integer>>() : res;
    }
 
    private List<List<Integer>> sub(int[] num, int target, int index, int numbers) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if (target == 0 && numbers == 0) {
            result.add(new ArrayList<Integer>());
            return result;
        }
        if (numbers < 0 || (index >= num.length || num[index] > target)) {
            return null;
        }
         
        for (int i = index; i < num.length; i++) {
            List<List<Integer>> lists = sub(num, target - num[i], i+1, numbers-1);
            if (lists != null && lists.size() > 0) {
                for (List<Integer> list : lists) {
                    list.add(0, num[i]);
                    result.add(list);
                }
            }
            int tmp = i + 1;
            while (tmp < num.length && num[tmp] == num[i]) {
                tmp++;
            }
            i = tmp - 1;
        }
        return result;
    }
}

Solution 2:
注意最里层对于重复数字的处理,只有当num[start] + num[end] == twoSumTarget满足时,才跳过剩下的重复数字,否则e.g. target= 4, 对于[2,2,4],如果先跳过重复数字的话[2,2]会miss

public class Solution {
    public List<List<Integer>> fourSum(int[] num, int target) {
        Arrays.sort(num);
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        for (int i = 0; i < num.length; i++) {
            for (int j = i + 1; j < num.length; j++) {
                int twoSumTarget = target - num[i] - num[j];
                int start = j + 1, end = num.length - 1;
                while (start < end) {
                    if (num[start] + num[end] == twoSumTarget) {
                        List<Integer> list = new ArrayList<Integer>();
                        list.add(num[i]);
                        list.add(num[j]);
                        list.add(num[start]);
                        list.add(num[end]);
                        result.add(list);
                        int tmp = start + 1;
                        while (tmp < end && num[tmp] == num[start]) {
                            tmp++;
                        }
                        start = tmp;
                        tmp = end - 1;
                        while (tmp > start && num[tmp] == num[end]) {
                            tmp--;
                        }
                        end = tmp;
                    } else if (num[start] + num[end] < twoSumTarget) {
                        start++;
                    } else {
                        end--;
                    }
                }
                int tmp = j + 1;
                while (tmp < num.length && num[tmp] == num[j]) {
                    tmp++;
                }
                j = tmp - 1;
            }
            int tmp = i + 1;
            while (tmp < num.length && num[tmp] == num[i]) {
                tmp++;
            }
            i = tmp - 1;
        }
        return result;
    }
}

Solution 3:另外一种解法是利用3sum

public class Solution {
    public List<List<Integer>> fourSum(int[] num, int target) {
        Arrays.sort(num);
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        for (int i = 0 ;i < num.length - 3; i++) {
        	List<List<Integer>> tmp = threeSum(num, i + 1, target - num[i]);
            if (tmp != null && !tmp.isEmpty()) {
                for (List<Integer> list : tmp) {
                    list.add(0, num[i]);
                    result.add(list);
                }
            }
            while (i + 1 < num.length && num[i+1] == num[i]) {
                i++;
            }
        }
        return result;
    }
    private List<List<Integer>> threeSum(int[] num, int index, int target) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        for (int i = index; i < num.length - 2; i++) {
            int sum = target - num[i];
            int start = i+1, end = num.length - 1;
            while (start < end) {
                if (num[start] + num[end] == sum) {
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(num[i]);
                    list.add(num[start]);
                    list.add(num[end]);
                    result.add(list);
                    while (start + 1 < end && num[start+1] == num[start]) {
                        start++;
                    }
                    while (end - 1 > start && num[end-1] == num[end]) {
                        end--;
                    }
                    start++;
                    end--;
                } else if (num[start] + num[end] < sum) {
                    while (start + 1 < end && num[start+1] == num[start]) {
                        start++;
                    }
                    start++;
                } else {
                    while (end - 1 > start && num[end-1] == num[end]) {
                        end--;
                    }
                    end--;
                }
            }
            while (i + 1 < num.length && num[i+1] == num[i]) {
                i++;
            }
        }
        return result;
    }
}

Codility 3.2 MinAvgTwoSlice

A non-empty zero-indexed array A consisting of N integers is given. A pair of integers (P, Q), such that 0 ≤ P < Q < N, is called a slice of array A (notice that the slice contains at least two elements). The average of a slice (P, Q) is the sum of A[P] + A[P + 1] + … + A[Q] divided by the length of the slice. To be precise, the average equals (A[P] + A[P + 1] + … + A[Q]) / (Q − P + 1).
For example, array A such that:
A[0] = 4
A[1] = 2
A[2] = 2
A[3] = 5
A[4] = 1
A[5] = 5
A[6] = 8
contains the following example slices:
slice (1, 2), whose average is (2 + 2) / 2 = 2;
slice (3, 4), whose average is (5 + 1) / 2 = 3;
slice (1, 4), whose average is (2 + 2 + 5 + 1) / 4 = 2.5.
The goal is to find the starting position of a slice whose average is minimal.


不熟练,容易出错,需要练习。

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        double prevAv = ((double)A[0] + A[1]) / 2;
        int prevIndex = 0;
        double minAv = prevAv;
        int result = prevIndex;
        for (int i = 2; i < A.length; i++) {
            double curAv = (prevAv * (i - prevIndex) + A[i]) / (i - prevIndex + 1);
            if (A[i] + A[i-1] >= curAv * 2) {
                prevAv = curAv;
            } else {
                prevAv = ((double)A[i] + A[i-1]) / 2;
                prevIndex = i - 1;
            }
            if (prevAv < minAv) {
                minAv = prevAv;
                result = prevIndex;
            }
        }
        return result;
    }
}

Codility 7.1 Max Double Slice Sum

A non-empty zero-indexed array A consisting of N integers is given. A triplet (X, Y, Z), such that 0 ≤ X < Y < Z < N, is called a double slice.

The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + … + A[Y − 1] + A[Y + 1] + A[Y + 2] + … + A[Z − 1].

For example, array A such that:

    A[0] = 3
    A[1] = 2
    A[2] = 6
    A[3] = -1
    A[4] = 4
    A[5] = 5
    A[6] = -1
    A[7] = 2

contains the following example double slices:

  • double slice (0, 3, 6), sum is 2 + 6 + 4 + 5 = 17,
  • double slice (0, 3, 7), sum is 2 + 6 + 4 + 5 − 1 = 16,
  • double slice (3, 4, 5), sum is 0.

The goal is to find the maximal sum of any double slice.


这道题其实和leetcode 的Best Time to Buy and Sell Stock III是一道题。

class Solution {
    public int solution(int[] A) {
        int[] fromLeft = new int[A.length];
        int[] fromRight = new int[A.length];
        int max = 0;
        for (int i = 2; i < A.length; i++) {
            fromLeft[i] = Math.max(0, fromLeft[i-1] + A[i-1]);
        }
        for (int i = A.length - 3; i >= 0; i--) {
            fromRight[i] = Math.max(0, fromRight[i+1] + A[i+1]);
        }
        for (int i = 1; i < A.length - 1; i++) {
            max = Math.max(max, fromLeft[i] + fromRight[i]);
        }
        return max;
    }
}

Codility 3.3 Genomic-range-query

A DNA sequence can be represented as a string consisting of the letters A, C, G and T, which correspond to the types of successive nucleotides in the sequence. Each nucleotide has an impact factor, which is an integer. Nucleotides of types A, C, G and T have impact factors of 1, 2, 3 and 4, respectively. You are going to answer several queries of the form: What is the minimal impact factor of nucleotides contained in a particular part of the given DNA sequence?
The DNA sequence is given as a non-empty string S = S[0]S[1]…S[N-1] consisting of N characters. There are M queries, which are given in non-empty arrays P and Q, each consisting of M integers. The K-th query (0 ≤ K < M) requires you to find the minimal impact factor of nucleotides contained in the DNA sequence between positions P[K] and Q[K] (inclusive).
For example, consider string S = CAGCCTA and arrays P, Q such that:
P[0] = 2 Q[0] = 4
P[1] = 5 Q[1] = 5
P[2] = 0 Q[2] = 6
The answers to these M = 3 queries are as follows:
The part of the DNA between positions 2 and 4 contains nucleotides G and C (twice), whose impact factors are 3 and 2 respectively, so the answer is 2.
The part between positions 5 and 5 contains a single nucleotide T, whose impact factor is 4, so the answer is 4.
The part between positions 0 and 6 (the whole string) contains all nucleotides, in particular nucleotide A whose impact factor is 1, so the answer is 1.
Complexity:
expected worst-case time complexity is O(N+M);
expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).


class Solution {
    public int[] solution(String S, int[] P, int[] Q) {
        // write your code in Java SE 8
        int[][] store = new int[S.length()][4];
        int[] result = new int[P.length];
        for (int i = 0; i < S.length(); i++) {
            for (int j = 0; j < 4; j++) {
                store[i][j] = i == 0 ? 0 : store[i-1][j];
            }
            int index = 0;
            switch(S.charAt(i)) {
                case 'A' : index = 0; break;
                case 'C' : index = 1; break;
                case 'G' : index = 2; break;
                case 'T' : index = 3; break;
            }
            store[i][index]++;
        }
        for (int i = 0; i < P.length; i++) {
            if ((P[i] < 1 && store[Q[i]][0] > 0) || (P[i] >= 1 && store[Q[i]][0] - store[P[i]-1][0] > 0)) {
                result[i] = 1;
            } else if ((P[i] < 1 && store[Q[i]][1] > 0) || (P[i] >= 1 && store[Q[i]][1] - store[P[i]-1][1] > 0)) {
                result[i] = 2;
            } else if ((P[i] < 1 && store[Q[i]][2] > 0) || (P[i] >= 1 && store[Q[i]][2] - store[P[i]-1][2] > 0)) {
                result[i] = 3;
            } else {
                result[i] = 4;
            }
        }
        return result;
    }
}

Codility 3.1 Count divisible

Write a function:
class Solution { public int solution(int A, int B, int K); }
that, given three integers A, B and K, returns the number of integers within the range [A..B] that are divisible by K, i.e.:
{ i : A ≤ i ≤ B, i mod K = 0 }
For example, for A = 6, B = 11 and K = 2, your function should return 3, because there are three numbers divisible by 2 within the range [6..11], namely 6, 8 and 10.
Assume that:
A and B are integers within the range [0..2,000,000,000];
K is an integer within the range [1..2,000,000,000];
A ≤ B.
Complexity:
expected worst-case time complexity is O(1);
expected worst-case space complexity is O(1).


class Solution {
    public int solution(int A, int B, int K) {
        // write your code in Java SE 8
        if (A % K == 0) {
            return 1 + (B - A)/K;
        } else {
            int toSkip = K - A % K;
            if (B < A + toSkip) {
                return 0;
            }
            return 1 + (B - A - toSkip) / K;
        }
    }
}