lintcode分类算法题总结

1 - 从strStr谈面试技巧与代码风格

13.字符串查找

要求:如题

思路:(自写AC)双重循环,内循环读完则成功

还可以用Rabin,KMP算法等

    public int strStr(String source, String target) {
        if (source == null || target == null) {
            return -1;
        }
        char[] sources = source.toCharArray();
        char[] targets = target.toCharArray();
        int m = sources.length;
        int n = targets.length;
        for (int i = 0; i <= m - n; i++) {
            int j = 0;
            while (j < n && sources[i + j] == targets[j]) {
                j++;
            }
            if (j == n) {
                return i;
            }
        }
        return -1;
    }
View Code

2017-01-16

594.StrStr II

要求:时间复杂度为O(m+n)

思路:用Rabin Karp算法,这种算法沿用了暴力法,但加入了hashcode的思想,因为target和substring的hashcode进行对比只需要O(1)时间复杂度,而且substring变成下一个子串也只需要进行一次O(1)的运算(就是把头部减掉,再加上新的字符的hashcode),等target和substring的hashcode相等再对它们进行真正的字符串比较

warn:由于hashcode大小有可能越界,所以要对其进行一个固定BASE的取模运算,如果变成负的时候要把它加一个BASE变回正数

public class Solution {
    public final int BASE = 1000000;
    /**
     * @param source a source string
     * @param target a target string
     * @return an integer as index
     */
    public int strStr2(String source, String target) {
        if (source == null || target == null) {
            return -1;
        }
        int m = target.length();
        if (m == 0) {
            return 0;
        }
        // count 31 ^ m
        int power = 1;
        for (int i = 0; i < m; i++) {
            power = (power * 31) % BASE;
        }
        // target hashcode
        int targetCode = 0;
        for (int i = 0; i < m; i++) {
            targetCode = (targetCode * 31 + target.charAt(i)) % BASE;
        }
        // substring hashcode
        int substrCode = 0;
        for (int i = 0; i < source.length(); i++) {
            substrCode = (substrCode * 31 + source.charAt(i)) % BASE;
            if (i < m - 1) {
                continue;
            }
            // 超过m长度后减去头字符的hashcode
            if (i >= m) {
                substrCode = substrCode - (power * source.charAt(i - m)) % BASE;
                //当前字符的hashcode比之前取模后的字符串的hashcode大就变成负数
                if (substrCode < 0) {
                    substrCode += BASE;
                }
            }
            if (substrCode == targetCode) {
                if (source.substring(i - m + 1, i + 1).equals(target)) {
                    return i - m + 1;
                }
            }
        }
        return -1;
    }
}
View Code

2017-09-19

17.子集

要求:集合中不含重复,答案中集合的元素升序排列

思路:(自写修改AC)DFS模板,背

warn:记得deep copy

    public ArrayList<ArrayList<Integer>> subsets(int[] nums) {
        ArrayList<ArrayList<Integer>> results = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return results;
        }
        ArrayList<Integer> subset = new ArrayList<>();
        //排序非必要
        Arrays.sort(nums);
        //从空集开始
        dfsHelper(nums, 0, subset, results);
        return results;
    }
    private void dfsHelper(int[] nums,
                           int startIndex,
                           ArrayList<Integer> subset,
                           ArrayList<ArrayList<Integer>> results) {
        //deep copy
        results.add(new ArrayList<Integer>(subset));
        for (int i = startIndex; i < nums.length; i++) {
            subset.add(nums[i]);
            dfsHelper(nums, i + 1, subset, results);
            subset.remove(subset.size() - 1);
        }
    }
View Code

2017-01-16

18.带重复元素的子集

要求:集合中有重复元素,不能出现重复的子集

思路:模板中加入了nums[i] == nums[i - 1] && i != startIndex,表示新一轮从startIndex开始加入的不能重复

public class Solution {
    /*
     * @param nums: A set of numbers.
     * @return: A list of lists. All valid subsets.
     */
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> results = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return results;
        }
        Arrays.sort(nums);
        List<Integer> subset = new ArrayList<>();
        dfsHelper(nums, 0, subset, results);
        return results;
    }
    private void dfsHelper(int[] nums,
                           int startIndex,
                           List<Integer> subset,
                           List<List<Integer>> results) {
        results.add(new ArrayList<>(subset));
        for (int i = startIndex; i < nums.length; i++) {
            if (i != 0 && nums[i] == nums[i - 1] && i != startIndex) {
                continue;
            }
            subset.add(nums[i]);
            dfsHelper(nums, i + 1, subset, results);
            subset.remove(subset.size() - 1);
        }
    }
}
View Code

2017-09-19

15.全排序

要求:没有重复元素

思路:与子集一样,但要加入判断数组visited[],而且还要判断每次生成的list长度是否等于列表长度才加入结果中

 View Code

2017-09-19

16.带有重复元素的排序

要求:如题

思路:与含有重复元素的子集一样,要判断当前的数是否与上一个数一样,并且判断上一个数是否已放在排序中

class Solution {
    /**
     * @param nums: A list of integers.
     * @return: A list of unique permutations.
     */
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        if (nums == null) {
            return lists;
        }
        if (nums.length == 0) {
            lists.add(list);
            return lists;
        }
        Arrays.sort(nums);
        int[] visited = new int[nums.length];
        helper(nums, visited, list, lists);
        return lists;
    }
    private void helper(int[] nums, int[] visited,
                        List<Integer> list, List<List<Integer>> lists) {
        if (list.size() == nums.length) {
            lists.add(new ArrayList<Integer>(list));
        }
        for (int i = 0; i < nums.length; i++) {
            if (visited[i] == 1) {
                continue;
            }
            if (i != 0 && nums[i] == nums[i - 1] && visited[i - 1] == 0) {
                continue;
            }
            visited[i] = 1;
            list.add(nums[i]);
            helper(nums, visited, list, lists);
            list.remove(list.size() - 1);
            visited[i] = 0;
        }
    }
}
View Code

2017-09-19

2 - 二分法与排序数组

457.二分查找标准写法

注意:循环判断条件、double check

    public int findPosition(int[] nums, int target) {
        // write your code here
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int start = 0, end = nums.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (nums[start] == target) {
            return start;
        }
        if (nums[end] == target) {
            return end;
        }
        return -1;
    }
View Code

2018-01-17

458.目标最后位置

要求:二分法找目标最后一次

思路:(自写但有错误)double check时候要把end放在前面

    public int lastPosition(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int start = 0, end = nums.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] == target) {
                start = mid;
            } else if (nums[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (nums[end] == target) {
            return end;
        }
        if (nums[start] == target) {
            return start;
        }
        return -1;
    }
View Code

2017-01-23

141.x的平方根

要求:二分法找

思路:(自写有错误)定义时应为long,防止溢出

    public int sqrt(int x) {
        if (x == 0) {
            return 0;
        }
        long start = 1, end = x;
        while (start + 1 < end) {
            long mid = start + (end - start) / 2;
            if (mid * mid == x) {
                return (int) mid;
            } else if (mid * mid < x) {
                start = mid;
            } else {
                end = mid;
            }
        }
        return (int) start;
    }
View Code

2017-01-23

14.二分查找

要求:找第一次出现的位置

思路:(自写一次AC)注意dc时候把start放前面

    public int binarySearch(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int start = 0, end = nums.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] == target) {
                end = mid;
            } else if (nums[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (nums[start] == target) {
            return start;
        }
        if (nums[end] == target) {
            return end;
        }
        return -1;
    }
View Code

2017-01-23

447.在大数组中查找

要求:只能通过get来获得一个位置,不知道数组长度,获取target第一次出现位置

思路:(自写一次AC)多加了一个找长度的while

    public int searchBigSortedArray(ArrayReader reader, int target) {
        //找length
        int length = 1;
        while (reader.get(length - 1) < target) {
            length *= 2;
        }
        int start = 0, end = length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (reader.get(mid) == target) {
                end = mid;
            } else if (reader.get(mid) < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (reader.get(start) == target) {
            return start;
        }
        if (reader.get(end) == target) {
            return end;
        }
        return -1;
    }
View Code

2017-01-23

183.木材加工

要求:找满足数量k的最长分法

思路:(自写出错)二分答案,mid选的是长度,判断的是分了之后的结果是否满足k,自写时没加入count方法所以double check出错

    public int woodCut(int[] L, int k) {
        if (L == null || L.length == 0) {
            return 0;
        }
        Arrays.sort(L); //也可以遍历求最大值
        int start = 1, end = L[L.length - 1];
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (count(L, mid) >= k) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (count(L, start) >= k) {
            return start;
        }
        if (count(L, end) >= k) {
            return end;
        }
        return 0;
    }
    //count方法求每次的数量
    private int count(int[] L, int len) {
        int sum = 0;
        for (int i = 0; i < L.length; i++) {
            sum += L[i] / len;
        }
        return sum;
    }
View Code

2017-01-23

159.寻找旋转排序数组(RSA)中的最小值

要求:升序数组旋转后,求旋转的那个最小值点

思路:(掌握思路后自写一次AC)选最后一个数作为target,然后求小于等于target的第一个位置上的数

    public int findMin(int[] nums) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int start = 0, end = nums.length - 1;
        //choose last number as target
        //and find the first position if nums[i] <= target
        int target = nums[nums.length - 1];
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] <= target) {
                end = mid;
            } else {
                start = mid;
            }
        }
        //double check
        if (nums[start] <= target) {
            return nums[start];
        } else {
            return nums[end];
        }
    }
View Code

2017-01-24

75.寻找峰值

要求:找出任意峰值点

思路:(掌握思路一次AC)与旁边的比较,if先写start = mid,else为end = mid,最后要dc,属于Half Half法

tips:end取length - 2

    public int findPeak(int[] A) {
        if (A == null || A.length == 0) {
            return -1;
        }
        int start = 0, end = A.length - 2; //peak can only happen before len - 2
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (A[mid] < A[mid + 1]) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (A[start] < A[end]) {
            return end;
        } else {
            return start;
        }
    }
View Code

2017-01-24

74.第一个错误的代码版本

要求:出现错误后就一直错,用接口判断是否错

思路:(读清楚题后AC)XXOO找第一个

    public int findFirstBadVersion(int n) {
        if (n == 0) {
            return 0;
        }
        int start = 1, end = n;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (SVNRepo.isBadVersion(mid)) {
                end = mid;
            } else {
                start = mid;
            }
        }
        if (SVNRepo.isBadVersion(start)) {
            return start;
        } else {
            return end;
        }
    }
View Code

2017-01-25

62.搜索旋转排序数组

要求:在RSA中找出target

思路:(答案)属于Half Half,用start来判断mid在断点左还是右,左的时候利用start和mid夹逼,右的时候用mid和end夹

    public int search(int[] A, int target) {
        if (A == null || A.length == 0) {
            return -1;
        }
        int start = 0, end = A.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (A[mid] == target) {
                return mid;
            }
            if (A[start] < A[mid]) {
                if (A[start] <= target && target <= A[mid]) {
                    end = mid;
                } else {
                    start = mid;
                }
            } else {
                if (A[mid] <= target && target <= A[end]) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
        }
        if (A[start] == target) {
            return start;
        }
        if (A[end] == target) {
            return end;
        }
        return -1;
    }
View Code

2017-01-25

437.书籍复印copy books

要求:pages数组表示每本书的页数,求k个人复印的最短时间

思路:(答案,还不完全理解二分答案,先算出pages最大和总数,最快的情况是最大的复印完就全部复印完,最坏的情况是只有一个人复印全部书,所以是总数,没看懂countCopiers方法

    public int copyBooks(int[] pages, int k) {
        if (pages.length == 0) {
            return 0;
        }
        int total = 0;
        int max = pages[0];
        for (int i = 0; i < pages.length; i++) {
            total += pages[i];
            if (max < pages[i]) {
                max = pages[i];
            }
        }
        int start = max;
        int end = total;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (countCopiers(pages, mid) > k) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (countCopiers(pages, start) <= k) {
            return start;
        } else {
            return end;
        }
    }
    private int countCopiers(int[] pages, int limit) {
        int copiers = 1;
        int sum = pages[0];
        for (int i = 1; i < pages.length; i++) {
            if (sum + pages[i] > limit) {
                copiers++;
                sum = 0;
            }
            sum += pages[i];
        }
        return copiers;
    }
View Code

2017-01-25

459.closest number in sorted array

要求:找出排序数组中与target最接近的数,不要求第一个还是最后一个

思路:(自写AC)在模板基础上加多一个判断,记得double check

    public int closestNumber(int[] A, int target) {
        if (A == null || A.length == 0) {
            return -1;
        }
        int start = 0, end = A.length - 1;
        int diff = Math.abs(A[0] - target);
        int index = 0;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (Math.abs(A[mid] - target) < diff) {
                diff = Math.abs(A[mid] - target);
                index = mid;
            }
            if (A[mid] == target) {
                return mid;
            } else if (A[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (Math.abs(A[start] - target) < diff) {
            return start;
        }
        if (Math.abs(A[end] - target) < diff) {
            return end;
        }
        return index;
    }
View Code

2017-03-08

28.search a 2D matrix

要求:在二维矩阵查找一个数是否存在

思路:(自写AC)找右上或左下

    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        int row = 0, col = matrix[0].length - 1;
        while (row < matrix.length && col >= 0) {
            if (matrix[row][col] == target) {
                return true;
            } else if (matrix[row][col] < target) {
                row++;
            } else {
                col--;
            }
        }
        return false;
    }
View Code

2017-03-08

38.search a 2D matrix II

要求:找出target出现几次

思路:和上题一样,只不过相等时要行与列同时变化

 View Code

2017-09-25

585.maximum number in mountain sequence

要求:序列先升后降 找顶点,与75题比较差别是这个序列中只存在一个峰值,而75可能有多个

思路:(自写AC)与旁边比较

    public int mountainSequence(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return nums[0];
        }
        int start = 0, end = nums.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) {
                return nums[mid];
            } else if (nums[mid] > nums[mid - 1]) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (nums[start] > nums[start + 1]) {
            return nums[start];
        } else {
            return nums[end];
        }
    }
View Code

2017-03-08

600.smallest rectangle enclosing black pixels(hard)

要求:image矩阵中包括1、0,其中1互相连同且image中只有一块,给出其中一个1的坐标,求把1的区域围绕起来的最小矩形

思路:(答案,没自写,答案的style不好二分法,把给出坐标的四个方向都做一次二分,求出上下左右

    public int minArea(char[][] image, int x, int y) {
        // Write your code here
        int m = image.length;
        if (m == 0)
            return 0;
        int n = image[0].length;
        if (n == 0)
            return 0;

        int start = y;
        int end = n - 1;
        int mid;
        while (start < end) {
            mid = start + (end - start) / 2 + 1;
            if (checkColumn(image, mid)) {
                start = mid;
            } else {
                end = mid - 1;
            }
        }
        int right = start;
        
        start = 0;
        end = y;
        while (start < end) {
            mid = start + (end - start) / 2;
            if (checkColumn(image, mid)) {
                end = mid;
            } else {
                start = mid + 1;
            }
        }
        int left = start;
        
        start = x;
        end = m - 1;
        while (start < end) {
            mid = start + (end - start) / 2 + 1;
            if (checkRow(image, mid)) {
                start = mid;
            } else {
                end = mid - 1;
            }
        }
        int down = start;
        
        start = 0;
        end = x;
        while (start < end) {
            mid = start + (end - start) / 2;
            if (checkRow(image, mid)) {
                end = mid;
            } else {
                start = mid + 1;
            }
        }
        int up = start;
        
        return (right - left + 1) * (down - up + 1);
    }
    
    private boolean checkColumn(char[][] image, int col) {
        for (int i = 0; i < image.length; i++) {
            if (image[i][col] == '1') {
                return true;
            }
        }
        return false;
    }
    
    private boolean checkRow(char[][] image, int row) {
        for (int j = 0; j < image[0].length; j++) {
            if (image[row][j] == '1') {
                return true;
            }
        }
        return false;
    }
View Code

还可以用bfs来做!

2017-03-08

462.目标出现总和

要求:找出target出现的次数,数组为升序

思路(自写):二分,找到target后用left与right指针找出第一次发现后,两边分别还有多少个相同的数

public class Solution {
    /*
     * @param A: A an integer array sorted in ascending order
     * @param target: An integer
     * @return: An integer
     */
    public int totalOccurrence(int[] A, int target) {
        // write your code here
        if (A == null || A.length == 0) {
            return 0;
        }
        int start = 0, end = A.length - 1;
        int num = 0;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (A[mid] == target) {
                num++;
                int left, right;
                left = mid - 1;
                right = mid + 1;
                while (left >= start && A[left] == A[mid]) {
                    num++;
                    left--;
                }
                while (right <= end && A[right] == A[mid]) {
                    num++;
                    right++;
                }
                return num;
            } else if (A[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (A[start] == target) {
            num++;
        }
        if (A[end] == target) {
            num++;
        }
        return num;
    }
}
View Code

2017-09-25

254.drop eggs

要求:提供两个鸡蛋,总共有n层楼,求出最坏情况下,需要扔多少次,才能找到恰好扔坏鸡蛋的楼层k

思路:转化成x + (x - 1) + ... + 1 >= n,x就是答案(我也不知道为什么)

其实还可以用动态规划来做

public class Solution {
    /*
     * @param n: An integer
     * @return: The sum of a and b
     */
    public int dropEggs(int n) {
        // write your code here
        long ans = 0;
        for (int i = 1; ; i++) {
            ans += (long)i;
            if (ans >= (long)n) {
                return i;
            }
        }
    }
}
View Code

2017-09-25

460.找出k个最接近的数

要求:在升序数组中,找出与target最接近的k个数,返回结果时,从最接近到最远的数依次排序,若差值相等时先排小的数

思路:先找到最接近的数,然后在它两边再寻找k - 1个,用两个指针,判断两边谁的差值小谁先进

public class Solution {
    /*
     * @param A: an integer array
     * @param target: An integer
     * @param k: An integer
     * @return: an integer array
     */
    public int[] kClosestNumbers(int[] A, int target, int k) {
        // write your code here
        if (A == null || A.length == 0) {
            return A;
        }
        if (k > A.length) {
            return A;
        }
        int[] results = new int[k];
        //find the first one
        int index = findFirstOne(A, target);
        int start = index;
        int end = index + 1;
        for (int i = 0; i < k; i++) {
            //start < 0 , end >= length
            if (start < 0) {
                results[i] = A[end++];
            } else if (end >= A.length) {
                results[i] = A[start--];
            } else {
                //begin from the smaller
                if (target - A[start] <= A[end] - target) {
                    results[i] = A[start--];
                } else {
                    results[i] = A[end++];
                }
            }
        }
        return results;
    }
    private int findFirstOne(int[] A, int target) {
        int start = 0, end = A.length - 1;
        int diff = Math.abs(A[0] - target);
        int index = 0;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (Math.abs(A[mid] - target) < diff) {
                diff = Math.abs(A[mid] - target);
                index = mid;
            }
            if (A[mid] == target) {
                return mid;
            } else if (A[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (Math.abs(A[start] - target) < diff) {
            return start;
        }
        if (Math.abs(A[end] - target) < diff) {
            return end;
        }
        return index;
    }
}
View Code

2017-09-25

61.搜索区间

要求:找出target在数组中出现的区间

思路(自写):找出第一个,然后从这开始循环判断

public class Solution {
    /*
     * @param A: an integer sorted array
     * @param target: an integer to be inserted
     * @return: a list of length 2, [index1, index2]
     */
    public int[] searchRange(int[] A, int target) {
        // write your code here
        if (A == null || A.length == 0) {
            return new int[]{-1, -1};
        }
        int[] result = new int[2];
        int index = findFirstOne(A, target);
        result[0] = index;
        while (index != -1 && index + 1 < A.length
               && A[index] == A[index + 1]) {
            index++;
        }
        result[1] = index;
        return result;
    }
    private int findFirstOne(int[] A, int target) {
        int start = 0, end = A.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (A[mid] >= target) {
                end = mid;
            } else {
                start = mid;
            }
        }
        if (A[start] == target) {
            return start;
        }
        if (A[end] == target) {
            return end;
        }
        return -1;
    }
}
View Code

2017-09-27

3 - 二叉树与分治法

97.二叉树的最大深度

要求:如题

思路1:(答案)分治法,找出左右节点的最大值 + 1 = 当前父节点的深度

    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return Math.max(left, right) + 1;
    }
View Code

2017-01-26

思路2:(答案)遍历法需要全局变量depth,每次遍历到子节点curDepth + 1,更新全局变量depth,遍历到最后为止

public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: An integer.
     */
    private int depth; //全局变量
    public int maxDepth(TreeNode root) {
        depth = 0;
        helper(root, 1);
        return depth;
    }
    private void helper(TreeNode root, int curDepth) {
        if (root == null) {
            return;
        }
        if (curDepth > depth) {
            depth = curDepth;
        }
        //遍历
        helper(root.left, curDepth + 1);
        helper(root.right, curDepth + 1);
    }
}
View Code

2017-01-26

480.二叉树的所有路径

要求:如题

思路1:(答案)分治法,分成两条路径,然后把路径的节点都加入到返回的结果中

warn:除了判断root == null,还要判断叶节点,因为要加入叶它自己

    public List<String> binaryTreePaths(TreeNode root) {
        List<String> paths = new ArrayList<String>();
        if (root == null) {
            return paths;
        }
        List<String> leftPaths = binaryTreePaths(root.left);
        List<String> rightPaths = binaryTreePaths(root.right);
        for (String path : leftPaths) {
            paths.add(root.val + "->" + path);
        }
        for (String path : rightPaths) {
            paths.add(root.val + "->" + path);
        }
        return paths;
    }
View Code

思路2:(答案)遍历法paths作为全局变量,然后通过helper一步步构建每个path,仍然要判断叶

    public List<String> binaryTreePaths(TreeNode root) {
        List<String> paths = new ArrayList<String>(); //全局变量
        if (root == null) {
            return paths;
        }
        helper(root, root.val + "", paths);
        return paths;
    }
    private void helper(TreeNode root, String path, List<String> paths) {
        if (root == null) {
            return;
        }
        //leaf
        if (root.left == null && root.right == null) {
            paths.add(path);
            return;
        }
        if (root.left != null) {
            helper(root.left, path + "->" + root.left.val, paths);
        }
        if (root.right != null) {
            helper(root.right, path + "->" + root.right.val, paths);
        }
    }
View Code

2017-01-26

596.和最小的子树Minimum Subtree

要求:找出和最小的子数所对应的根节点

思路1:(答案)traverse + divide conquer,在helper中使用divide conquer的思想来算当前的和sum

warn:helper中返回值不能是void,因为算left 和 right要有值

public class Solution {
    /**
     * @param root the root of binary tree
     * @return the root of the minimum subtree
     */
    //全局变量
    private TreeNode subtreeRoot = null;
    private int subtreeSum = Integer.MAX_VALUE;
    public TreeNode findSubtree(TreeNode root) {
        //traverse
        helper(root);
        return subtreeRoot;
    }
    private int helper(TreeNode root) {
        if (root == null) {
            return 0;
        }
        //divide conquer
        int sum = helper(root.left) + helper(root.right) + root.val;
        if (subtreeSum > sum) {
            subtreeSum = sum;
            subtreeRoot = root;
        }
        return sum;
    }
View Code

思路2:只用divide conquer,增加ResultType类来保存每次递归时的最小和minSum、对应的根节点subtreeRoot、当前的和Sum

public class Solution {
    /*
     * @param root: the root of binary tree
     * @return: the root of the minimum subtree
     */
    public class ResultType {
        public TreeNode subtreeRoot;
        public int minSum, sum;
        public ResultType(TreeNode subtreeRoot, int minSum, int sum) {
            this.subtreeRoot = subtreeRoot;
            this.minSum = minSum;
            this.sum = sum;
        }
    }
    public TreeNode findSubtree(TreeNode root) {
        // write your code here
        ResultType result = dfsHelper(root);
        return result.subtreeRoot;
    }
    private ResultType dfsHelper(TreeNode root) {
        if (root == null) {
            return new ResultType(null, Integer.MAX_VALUE, 0);
        }
        ResultType left = dfsHelper(root.left);
        ResultType right = dfsHelper(root.right);
        ResultType curr = new ResultType(root, left.sum + right.sum + root.val,
                                         left.sum + right.sum + root.val);
        if (left.minSum < curr.minSum) {
            curr.minSum = left.minSum;
            curr.subtreeRoot = left.subtreeRoot;
        }
        if (right.minSum < curr.minSum) {
            curr.minSum = right.minSum;
            curr.subtreeRoot = right.subtreeRoot;
        }
        return curr;
    }
}
View Code

2017-10-12

2017-01-26

597.平均值最大的子树Subtree with Maximum Average

要求:找出平均值最大的子树对应的根节点

思路:(答案)traverse + divide conquer,加入ResultType类来保存sum和size(这里创建了ResultType类的全局变量,也就是体现了traverse的思想),在helper中先用分治思想算出当前的sum与size,更新较大average保存在全局变量中,helper同时也保存当前的ResultType,因为这样才会有left 和 right的数据,由下层的递归得到

warn:在对比average时,若通过sum除以size会带来误差,应当转成乘法的不等式

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    //用ResultType来存储sum和size获得average
    private class ResultType {
        public int sum;
        public int size;
        public ResultType(int sum, int size) {
            this.sum = sum;
            this.size = size;
        }
    }
    //全局变量
    private TreeNode subtreeRoot = null;
    private ResultType subtreeResult = null;
    public TreeNode findSubtree2(TreeNode root) {
        helper(root);
        return subtreeRoot;
    }
    //有返回值的helper
    private ResultType helper(TreeNode root) {
        if (root == null) {
            return new ResultType(0, 0);
        }
        //divide & conquer
        ResultType left = helper(root.left);
        ResultType right = helper(root.right);
        //当前的结果
        ResultType currResult = new ResultType(left.sum + right.sum + root.val,
                                               left.size + right.size + 1);
        //相乘防止误差
        if (subtreeRoot == null || subtreeResult.sum * currResult.size
            < currResult.sum * subtreeResult.size) {
            subtreeResult = currResult;
            subtreeRoot = root;
        }
        return currResult;
    }
}
View Code

2017-01-27

453.二叉树的扁平化Flatten Binary Tree to Linked List

要求:如题

思路1:(答案)divide conquer,由于要返回最后一个点,所以要helper方法,把左子树最后一个连接右子树第一个,并把root的左节点代替右节点

warn:helper中作非空判断!

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     * @param root: a TreeNode, the root of the binary tree
     * @return: nothing
     */
    public void flatten(TreeNode root) {
        helper(root);
    }
    private TreeNode helper(TreeNode root) {
        if (root == null) {
            return null;
        }
        //把左右子树分别扁平化并找出最后一个数
        TreeNode leftLast = helper(root.left);
        TreeNode rightLast = helper(root.right);
        //左子树最后一个连接右子树第一个,并把root的左节点代替右节点
        if (leftLast != null) {
            leftLast.right = root.right;
            root.right = root.left;
            root.left = null;
        }
        //特殊判断
        if (rightLast != null) {
            return rightLast;
        }
        if (leftLast != null) {
            return leftLast;
        }
        return root;
    }
}
View Code

思路2:(答案)traverse,记录上一个点,然后把上一个点与当前进行连接

warn:要保存当前节点的右子节点??

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     * @param root: a TreeNode, the root of the binary tree
     * @return: nothing
     */
    //全局变量表示上一个节点
    private TreeNode lastNode = null;
    public void flatten(TreeNode root) {
        if (root == null) {
            return;
        }
        //上个节点连接当前
        if (lastNode != null) {
            lastNode.left = null;
            lastNode.right = root;
        }
        //更新lastNode
        lastNode = root;
        //保存当前节点的右子节点
        TreeNode right = root.right;
        flatten(root.left);
        flatten(right);
    }
}
View Code

思路3:还可以非递归来做,代码还没看懂

2017-01-27

595.二叉树的最长连续序列Binary Tree Longest Consecutive Sequence

要求:只能从上到下

思路1:(看完思路自写AC)traverse + divide conquer,helper中返回int类型

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param root the root of binary tree
     * @return the length of the longest consecutive sequence path
     */
    private int subtreeLen;
    public int longestConsecutive(TreeNode root) {
        subtreeLen = 0;
        helper(root);
        return subtreeLen;
    }
    private int helper(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = helper(root.left);
        int right = helper(root.right);
        int currLen = 1; //最起码有根一个
        if (root.left != null && root.val + 1 == root.left.val) {
            currLen = left + 1;
        }
        if (root.right != null && root.val + 1 == root.right.val) {
            currLen = right + 1;
        }
        if (currLen > subtreeLen) {
            subtreeLen = currLen;
        }
        return currLen;
    }
}
View Code

思路2:(根据答案自写)ResultType + divide conquer,ResultType包括maxFromRoot和maxInSubtree

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param root the root of binary tree
     * @return the length of the longest consecutive sequence path
     */
    private class ResultType{
        public int maxFromRoot;
        public int maxInSubtree;
        public ResultType(int maxFromRoot, int maxInSubtree) {
            this.maxFromRoot = maxFromRoot;
            this.maxInSubtree = maxInSubtree;
        }
    }
    public int longestConsecutive(TreeNode root) {
        return helper(root).maxInSubtree;
    }
    private ResultType helper(TreeNode root) {
        if (root == null) {
            return new ResultType(0, 0);
        }
        ResultType left = helper(root.left);
        ResultType right = helper(root.right);
        ResultType result = new ResultType(1, 0);
        if (root.left != null && root.val + 1 == root.left.val) {
            result.maxFromRoot = left.maxFromRoot + 1;
        }
        if (root.right != null && root.val + 1 == root.right.val) {
            result.maxFromRoot = right.maxFromRoot + 1;
        }
        result.maxInSubtree = Math.max(result.maxFromRoot,
                              Math.max(left.maxInSubtree, right.maxInSubtree));
        return result;
    }
}
View Code

2017-01-30

376.二叉树的路径和Binary tree Path Sum

要求:找出所有从上到下的和等于target的路径

思路:(看思路自写AC)traverse,用子集的方法,然后判断if (sum == target),把当前path加入到paths

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     * @param root the root of binary tree
     * @param target an integer
     * @return all valid paths
     */
    public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) {
        List<List<Integer>> paths = new ArrayList<>();
        if (root == null) {
            return paths;
        }
        //先把根放进去
        List<Integer> path = new ArrayList<>();
        path.add(root.val);
        helper(root, root.val, target, path, paths);
        return paths;
    }
    private void helper(TreeNode root, int sum, int target, List<Integer> path,
                        List<List<Integer>> paths) {
        if (root.left == null && root.right == null) {
            if (sum == target) {
                paths.add(new ArrayList<Integer>(path));
            }
            return;
        }
        if (root.left != null) {
            path.add(root.left.val);
            helper(root.left, sum + root.left.val, target, path, paths);
            path.remove(path.size() - 1);
        }
        if (root.right != null) {
            path.add(root.right.val);
            helper(root.right, sum + root.right.val, target, path, paths);
            path.remove(path.size() - 1);
        }
    }
}
View Code

2017-01-30

93.平衡二叉树Balanced Binary Tree

要求:判断左右子树的深度是否相差1以内

思路:(答案)divide conquer + ResultType,helper返回的是isBalanced和maxDepth

warn:递归中不仅要判断当前根节点是否平衡,还要判断它的两个子节点是否平衡:if (! left.isBalanced || ! right.isBalanced),只要两边有一个不平衡就整个不平衡

2017-10-12 

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: True if this Binary tree is Balanced, or false.
     */
    private class ResultType {
        public boolean isBalanced;
        public int maxDepth;
        public ResultType(boolean isBalanced, int maxDepth) {
            this.isBalanced = isBalanced;
            this.maxDepth = maxDepth;
        }
    }
    public boolean isBalanced(TreeNode root) {
        return helper(root).isBalanced;
    }
    private ResultType helper(TreeNode root) {
        if (root == null) {
            return new ResultType(true, 0);
        }
        ResultType left = helper(root.left);
        ResultType right = helper(root.right);
        if (Math.abs(left.maxDepth - right.maxDepth) > 1) {
            return new ResultType(false, -1);
        }
        if (!left.isBalanced || !right.isBalanced) {
            return new ResultType(false, -1);
        }
        int currDepth = Math.max(left.maxDepth, right.maxDepth) + 1;
        return new ResultType(true, currDepth);
    }
}
View Code

2017-01-30

 4 - 宽度优先搜索

69.二叉树的层级遍历

要求:如题

思路:(自写但没有bugfree)就是bfs的模板,分层表示要加size = queue.size()

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
 
 
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Level order a list of lists of integer
     */
    public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
        ArrayList<ArrayList<Integer>> results = new ArrayList<>();
        if (root == null) {
            return results;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        //bfs
        while (!queue.isEmpty()) {
            ArrayList<Integer> level = new ArrayList<>();
            //分层显示
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                //保存头节点
                TreeNode head = queue.poll();
                level.add(head.val);
                if (head.left != null) {
                    queue.offer(head.left);
                }
                if (head.right != null) {
                    queue.offer(head.right);
                }
            }
            results.add(level);
        }
        return results;
    }
}
View Code

2017-02-06

242.将二叉树按照层级转化成链表

要求:如题

思路:自写AC 与69类似,加入了链表的基本操作

public class Solution {
    /**
     * @param root the root of binary tree
     * @return a lists of linked list
     */
    public List<ListNode> binaryTreeToLists(TreeNode root) {
        // Write your code here
        List<ListNode> results = new ArrayList<>();
        if (root == null) {
            return results;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            ListNode dummy = new ListNode(0);
            ListNode node = dummy;
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode head = queue.poll();
                ListNode curr = new ListNode(head.val);
                node.next = curr;
                node = node.next;
                if (head.left != null) {
                    queue.offer(head.left);
                }
                if (head.right != null) {
                    queue.offer(head.right);
                }
            }
            results.add(dummy.next);
        }
        return results;
    }
}
View Code

2017-10-13

7.二叉树的序列化和反序列化

要求:如题

思路:序列化就直接bfs且加入时包括中间出现的null(#)并另外去除尾部的null,反序列化的时候需要注意判断左右儿子和当前在操作哪个节点

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
class Solution {
    /**
     * This method will be invoked first, you should design your own algorithm 
     * to serialize a binary tree which denote by a root node to a string which
     * can be easily deserialized by your own "deserialize" method later.
     */
    public String serialize(TreeNode root) {
        if (root == null) {
            return "{}";
        }
        ArrayList<TreeNode> list = new ArrayList<>();
        list.add(root);
        //bfs
        for (int i = 0; i < list.size(); i++) {
            TreeNode node = list.get(i);
            if (node == null) {
                continue;
            }
            list.add(node.left);
            list.add(node.right);
        }
        while (list.get(list.size() - 1) == null) {
            list.remove(list.size() - 1);
        }
        StringBuilder res = new StringBuilder();
        //把头节点加入
        res.append("{" + root.val);
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i) != null) {
                res.append("," + list.get(i).val);
            } else {
                res.append(",#");
            }
        }
        res.append("}");
        return res.toString();
    }
    
    /**
     * This method will be invoked second, the argument data is what exactly
     * you serialized at method "serialize", that means the data is not given by
     * system, it's given by your own serialize method. So the format of data is
     * designed by yourself, and deserialize it here as you serialize it in 
     * "serialize" method.
     */
    public TreeNode deserialize(String data) {
        if (data.equals("{}")) {
            return null;
        }
        //排除, {}并拆分
        String[] val = data.substring(1, data.length() - 1).split(",");
        ArrayList<TreeNode> list = new ArrayList<>();
        TreeNode root = new TreeNode(Integer.parseInt(val[0]));
        list.add(root);
        //指针标识当前操作哪个节点,以及判断是左还是右儿子
        int index = 0;
        boolean isLeftChild = true;
        for (int i = 1; i < val.length; i++) {
            if (!val[i].equals("#")) {
                TreeNode node = new TreeNode(Integer.parseInt(val[i]));
                //非空的才放进去list中
                list.add(node);
                if (isLeftChild) {
                    list.get(index).left = node;
                } else {
                    list.get(index).right = node;
                }
            }
            //到右儿子就操作下一个节点
            if (!isLeftChild) {
                index++;
            }
            //操作完左儿子变右儿子
            isLeftChild = !isLeftChild;
        }
        return root;
    }
}
View Code

2017-02-06

178.图是否是树

要求:如题,图用二维数组(邻接表)表示,二维数组有两列m(边数)行,数组的每个点就是图的点,同一行的点代表是neighbor

思路:图是树有两个条件:1.边数为点数 - 1;2.能连通

warn:构造无向图时一定要把双向都加入,所以在bfs时用另一个set去除已经加入过queue的neighbor

public class Solution {
    /**
     * @param n an integer
     * @param edges a list of undirected edges
     * @return true if it's a valid tree, or false
     */
    public boolean validTree(int n, int[][] edges) {
        if (n == 0) {
            return false;
        }
        //1.树的边数应为点数 - 1
        if (edges.length != n - 1) {
            return false;
        }
        //用邻接表定义图
        Map<Integer, Set<Integer>> graph = initializeGraph(n, edges);
        //2.从一个点出发能跑通
        Queue<Integer> queue = new LinkedList<>();
        Set<Integer> set = new HashSet<>();
        queue.offer(0);
        //排除相同点进入队列
        set.add(0);
        int visited = 0;
        while (!queue.isEmpty()) {
            int node = queue.poll();
            visited++;
            for (int neighbor : graph.get(node)) {
                if (set.contains(neighbor)) {
                    continue;
                }
                queue.offer(neighbor);
                set.add(neighbor);
            }
        }
        return visited == n;
    }
    private Map<Integer, Set<Integer>> initializeGraph(int n, int[][] edges) {
        //初始化HashMap
        Map<Integer, Set<Integer>> graph = new HashMap<>();
        for (int i = 0; i < n; i++) {
            graph.put(i, new HashSet<Integer>());
        }
        //把边放入
        for (int i = 0; i < edges.length; i++) {
            int u = edges[i][0];
            int v = edges[i][1];
            graph.get(u).add(v);
            graph.get(v).add(u);
        }
        return graph;
    }
}
View Code

2017-02-07

137.克隆图

要求:把图的点和边都复制

思路:1.bfs所有点,放进ArrayList中(相当于获得所有节点的引用)2.deep copy,真正new一个新的一样的节点,并把新老节点用map对应 3.运用老节点帮新节点找到邻居

warn:理解deep copy,分清楚创建的是新对象还是新引用

/**
 * Definition for undirected graph.
 * class UndirectedGraphNode {
 *     int label;
 *     ArrayList<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); }
 * };
 */
public class Solution {
    /**
     * @param node: A undirected graph node
     * @return: A undirected graph node
     */
    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        if (node == null) {
            return null;
        }
        //bfs来获得所有点
        ArrayList<UndirectedGraphNode> nodes = getNodes(node);
        //deep copy,并建立新老node的对应关系
        Map<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<>();
        for (UndirectedGraphNode n : nodes) {
            map.put(n, new UndirectedGraphNode(n.label));
        }
        //copy neighbor
        for (UndirectedGraphNode n : nodes) {
            UndirectedGraphNode newNode = map.get(n);
            for (UndirectedGraphNode neighbor : n.neighbors) {
                UndirectedGraphNode newNeighbor = map.get(neighbor);
                newNode.neighbors.add(newNeighbor);
            }
        }
        return map.get(node);
    }
    //标准对于图的bfs
    private ArrayList<UndirectedGraphNode> getNodes(UndirectedGraphNode node) {
        Queue<UndirectedGraphNode> queue = new LinkedList<>();
        Set<UndirectedGraphNode> set = new HashSet<>();
        queue.offer(node);
        set.add(node);
        while (!queue.isEmpty()) {
            UndirectedGraphNode head = queue.poll();
            for (UndirectedGraphNode neighbor : head.neighbors) {
                if (!set.contains(neighbor)) {
                    set.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
        //把set deep copy到ArrayList中
        return new ArrayList<UndirectedGraphNode>(set);
    }
}
View Code

2017-02-07

618.Search Graph Nodes

要求:找出value为target的最近的点

思路:bfs找出满足条件即可

/**
 * Definition for graph node.
 * class UndirectedGraphNode {
 *     int label;
 *     ArrayList<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { 
 *         label = x; neighbors = new ArrayList<UndirectedGraphNode>(); 
 *     }
 * };
 */
public class Solution {
    /**
     * @param graph a list of Undirected graph node
     * @param values a hash mapping, <UndirectedGraphNode, (int)value>
     * @param node an Undirected graph node
     * @param target an integer
     * @return the a node
     */
    public UndirectedGraphNode searchNode(ArrayList<UndirectedGraphNode> graph,
                                          Map<UndirectedGraphNode, Integer> values,
                                          UndirectedGraphNode node,
                                          int target) {
        Queue<UndirectedGraphNode> queue = new LinkedList<>();
        Set<UndirectedGraphNode> set = new HashSet<>();
        queue.offer(node);
        set.add(node);
        while (!queue.isEmpty()) {
            UndirectedGraphNode head = queue.poll();
            if (values.get(head) == target) {
                return head;
            }
            for (UndirectedGraphNode neighbor : head.neighbors) {
                if (!set.contains(neighbor)) {
                    set.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
        return null;
    }
}
View Code

2017-02-08

433.岛屿的个数

要求:矩阵中1代表岛屿,0代表海洋,相邻的1代表同一个岛,求岛的个数

思路:用bfs把1附近的1都标记为0

warn:判断越界,写inBound函数

public class Solution {
    /**
     * @param grid a boolean 2D matrix
     * @return an integer
     */
    class Node {
        int x;
        int y;
        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    public int numIslands(boolean[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int row  = grid.length;
        int col = grid[0].length;
        int island = 0;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (grid[i][j]) {
                    isNeighbor(grid, i, j);
                    island++;
                }
            }
        }
        return island;
    }
    private void isNeighbor(boolean[][] grid, int x, int y) {
        //坐标变换数组
        int[] deltaX = {0, 1, -1, 0};
        int[] deltaY = {1, 0, 0, -1};
        Queue<Node> queue = new LinkedList<>();
        queue.offer(new Node(x, y));
        //遍历过的标记为false
        grid[x][y] = false;
        //bfs访问四个方向
        while (!queue.isEmpty()) {
            Node head = queue.poll();
            for (int i = 0; i < 4; i++) {
                Node neighbor = new Node(head.x + deltaX[i], head.y + deltaY[i]);
                //判断越界
                if (!inBound(neighbor, grid)) {
                    continue;
                }
                if (grid[neighbor.x][neighbor.y]) {
                    grid[neighbor.x][neighbor.y] = false;
                    queue.offer(neighbor);
                }
            }
        }
    }
    private boolean inBound(Node node, boolean[][] grid) {
        int row  = grid.length;
        int col = grid[0].length;
        return node.x >= 0 && node.x < row && node.y >= 0 && node.y < col;
    }
}
View Code

2017-02-08

二刷 bfs时忘记把一开始的head放进去后,把它变成false,while循环中忘记每次更新head

2017-10-13

598.Zombie in Matrix

要求:0代表人,1代表僵尸,2代表墙,求多少天能够把人都变成僵尸

思路:1.数人头和把僵尸放到队列中 2.完整的三层循环的分层bfs(背),每一层就是经过一天 3.人数为0时返回天数

public class Solution {
    /**
     * @param grid  a 2D integer grid
     * @return an integer
     */
    class Node {
        int x, y;
        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    public int PEOPLE = 0;
    public int ZOMBIE = 1;
    public int[] deltaX = {0, 1, -1, 0};
    public int[] deltaY = {1, 0, 0, -1};
    public int zombie(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int people = 0;
        Queue<Node> queue = new LinkedList<>();
        int row = grid.length;
        int col = grid[0].length;
        //计算人的数量并把一开始的僵尸位置放到队列中
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (grid[i][j] == PEOPLE) {
                    people++;
                } else if (grid[i][j] == ZOMBIE) {
                    queue.offer(new Node(i, j));
                }
            }
        }
        if (people == 0) {
            return 0;
        }
        int days = 0;
        //完整的bfs
        while (!queue.isEmpty()) {
            //分层
            int size = queue.size();
            days++;
            for (int i = 0; i < size; i++) {
                Node head = queue.poll();
                for (int j = 0; j < 4; j++) {
                    Node neighbor = new Node(head.x + deltaX[j], head.y + deltaY[j]);
                    //判断是否越界以及是否为人
                    if (!isPeople(neighbor, grid)) {
                        continue;
                    }
                   grid[neighbor.x][neighbor.y] = ZOMBIE;
                   people--;
                   if (people == 0) {
                       return days;
                   }
                   queue.offer(neighbor);
                }
            }
        }
        return -1;
    }
    private boolean isPeople(Node node, int[][] grid) {
        int row = grid.length;
        int col = grid[0].length;
        if (node.x < 0 || node.x >= row) {
            return false;
        }
        if (node.y < 0 || node.y >= col) {
            return false;
        }
        return grid[node.x][node.y] == PEOPLE;
    }
}
View Code

2017-02-08

611.Knight Shortest Path

要求:骑士跳日字,计算从source位置到destination位置的步数

思路:(自写AC)1.坐标变换数组 2.完整的三层bfs 3.inBound方法

warn:不能用set标记已走过的地方,会超出内存范围,所以走过的地方标为BARRIER

/**
 * Definition for a point.
 * public class Point {
 *     public int x, y;
 *     public Point() { x = 0; y = 0; }
 *     public Point(int a, int b) { x = a; y = b; }
 * }
 */
public class Solution {
    /**
     * @param grid a chessboard included 0 (false) and 1 (true)
     * @param source, destination a point
     * @return the shortest path 
     */
    public boolean EMPTY = false;
    public boolean BARRIER = true;
    public int[] deltaX = {1, 1, 2, 2, -1, -1, -2, -2};
    public int[] deltaY = {2, -2, 1, -1, 2, -2, 1, -1};
    public int shortestPath(boolean[][] grid, Point source, Point destination) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return -1;
        }
        if (source.x == destination.x && source.y == destination.y) {
            return 0;
        }
        int rows = grid.length;
        int cols = grid[0].length;
        Queue<Point> queue = new LinkedList<>();
        queue.offer(source);
        //标记已走过
        grid[source.x][source.y] = BARRIER;
        //bfs
        int length = 0;
        while (!queue.isEmpty()) {
            length++;
            //分层
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Point head = queue.poll();
                //八个方向跳
                for (int j = 0; j < 8; j++) {
                    Point next = new Point(head.x + deltaX[j], head.y + deltaY[j]);
                    if (next.x == destination.x && next.y == destination.y) {
                        return length;
                    }
                    if (isBarrier(next, grid)) {
                        continue;
                    }
                    queue.offer(next);
                    grid[next.x][next.y] = BARRIER;
                }
            }
        }
        return -1;
    }
    private boolean isBarrier(Point p, boolean[][] grid) {
        int rows = grid.length;
        int cols = grid[0].length;
        if (p.x < 0 || p.x >= rows) {
            return true;
        }
        if (p.y < 0 || p.y >= cols) {
            return true;
        }
        return grid[p.x][p.y] == BARRIER;
    }
}
View Code

2017-02-09

573.Build Post Office II

要求:0代表office能建的位置,1代表房,2代表墙,求office能够到达所有房的最短路径

思路:求每间房到所有0点的距离,当求每个点时就可以把对应房间的距离加起来

class Coordinate {
    int x, y;
    public Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

public class Solution {
    public int EMPTY = 0;
    public int HOUSE = 1;
    public int WALL = 2;
    public int[][] grid;
    public int n, m;
    public int[] deltaX = {0, 1, -1, 0};
    public int[] deltaY = {1, 0, 0, -1};
    
    private List<Coordinate> getCoordinates(int type) {
        List<Coordinate> coordinates = new ArrayList<>();
        
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == type) {
                    coordinates.add(new Coordinate(i, j));
                }
            }
        }
        
        return coordinates;
    }
    
    private void setGrid(int[][] grid) {
        n = grid.length;
        m = grid[0].length;
        this.grid = grid;
    }
    
    private boolean inBound(Coordinate coor) {
        if (coor.x < 0 || coor.x >= n) {
            return false;
        }
        if (coor.y < 0 || coor.y >= m) {
            return false;
        }
        return grid[coor.x][coor.y] == EMPTY;
    }

    /**
     * @param grid a 2D grid
     * @return an integer
     */
    public int shortestDistance(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return -1;
        }
        
        // set n, m, grid
        setGrid(grid);
        
        List<Coordinate> houses = getCoordinates(HOUSE);
        int[][] distanceSum = new int[n][m];;
        int[][] visitedTimes = new int[n][m];;
        for (Coordinate house : houses) {
            bfs(house, distanceSum, visitedTimes);
        }
        
        int shortest = Integer.MAX_VALUE;
        List<Coordinate> empties = getCoordinates(EMPTY);
        for (Coordinate empty : empties) {
            if (visitedTimes[empty.x][empty.y] != houses.size()) {
                continue;
            }
            
            shortest = Math.min(shortest, distanceSum[empty.x][empty.y]);
        }
        
        if (shortest == Integer.MAX_VALUE) {
            return -1;
        }
        return shortest;
    }
    
    private void bfs(Coordinate start,
                     int[][] distanceSum,
                     int[][] visitedTimes) {
        Queue<Coordinate> queue = new LinkedList<>();
        boolean[][] hash = new boolean[n][m];
        
        queue.offer(start);
        hash[start.x][start.y] = true;
        
        int steps = 0;
        while (!queue.isEmpty()) {
            steps++;
            int size = queue.size();
            for (int temp = 0; temp < size; temp++) {
                Coordinate coor = queue.poll();
                for (int i = 0; i < 4; i++) {
                    Coordinate adj = new Coordinate(
                        coor.x + deltaX[i],
                        coor.y + deltaY[i]
                    );
                    if (!inBound(adj)) {
                        continue;
                    }
                    if (hash[adj.x][adj.y]) {
                        continue;
                    }
                    queue.offer(adj);
                    hash[adj.x][adj.y] = true;
                    distanceSum[adj.x][adj.y] += steps;
                    visitedTimes[adj.x][adj.y]++;
                } // direction
            } // for temp
        } // while
    }
}
View Code

(答案代码未仔细看,类似于上两题)

2017-02-09

127.拓扑排序

要求:如题,从入度0的出发,找出其中一个解

思路:(自写AC)1. 算每个点的入度 2. bfs每个点,对应的neighbor的入度 - 1,到入度为0时进入队列

/**
 * Definition for Directed graph.
 * class DirectedGraphNode {
 *     int label;
 *     ArrayList<DirectedGraphNode> neighbors;
 *     DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
 * };
 */
public class Solution {
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */    
    public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
        ArrayList<DirectedGraphNode> order = new ArrayList<>();
        if (graph == null) {
            return order;
        }
        // 1. count indegree
        Map<DirectedGraphNode, Integer> indegree = getIndegree(graph);
        // 2. bfs
        Queue<DirectedGraphNode> queue = new LinkedList<>();
        // find first node
        for (DirectedGraphNode node : graph) {
            if (indegree.get(node) == 0) {
                queue.offer(node);
                order.add(node);
            }
        }
        while (!queue.isEmpty()) {
            DirectedGraphNode head = queue.poll();
            for (DirectedGraphNode neighbor : head.neighbors) {
                indegree.put(neighbor, indegree.get(neighbor) - 1);
                if (indegree.get(neighbor) == 0) {
                    queue.offer(neighbor);
                    order.add(neighbor);
                }
            }
        }
        return order;
    }
    private Map<DirectedGraphNode, Integer> getIndegree(ArrayList<DirectedGraphNode> graph) {
        Map<DirectedGraphNode, Integer> map = new HashMap<>();
        // 初始化
        for (DirectedGraphNode node : graph) {
            map.put(node, 0);
        }
        for (DirectedGraphNode node : graph) {
            for (DirectedGraphNode neighbor : node.neighbors) {
                map.put(neighbor, map.get(neighbor) + 1);
            }
        }
        return map;
    }
}
View Code

2017-02-09

616.Course Schedule II

要求:把课程拓扑排序,给出的是二维数组表示的课程之间的关系

思路:(自写AC!) 1. 生成图 2. 算入度 3.bfs(与普通拓扑类似)

warn:注意特殊情况,判断是否有解!(index == numCourses时有解)

自写:

public class Solution {
    /**
     * @param numCourses a total of n courses
     * @param prerequisites a list of prerequisite pairs
     * @return the course order
     */
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] order = new int[numCourses];
        if (numCourses == 0) {
            return order;
        }
        //exceptional case
        if (numCourses != 0 && (prerequisites == null
            || prerequisites.length == 0 || prerequisites[0].length == 0)) {
            for (int i = 0; i < numCourses; i++) {
                order[i] = i;
            }
            return order;
        }
        // 1. initialize graph
        Map<Integer, ArrayList<Integer>> graph = initializeGraph(numCourses, prerequisites);
        // 2. count indegree
        Map<Integer, Integer> indegree = getIndegree(graph, numCourses);
        // 3. bfs
        int index = 0;
        Queue<Integer> queue = new LinkedList<>();
        // find start
        for (int i = 0; i < numCourses; i++) {
            if (indegree.get(i) == 0) {
                queue.offer(i);
                order[index++] = i;
            }
        }
        while (!queue.isEmpty()) {
            int head = queue.poll();
            for (int neighbor : graph.get(head)) {
                indegree.put(neighbor, indegree.get(neighbor) - 1);
                if (indegree.get(neighbor) == 0) {
                    queue.offer(neighbor);
                    order[index++] = neighbor;
                }
            }
        }
        if (index == numCourses) {
            return order;
        }
        return new int[0];
    }
    private Map<Integer, ArrayList<Integer>> initializeGraph(int numCourses, int[][] prerequisites) {
        Map<Integer, ArrayList<Integer>> graph = new HashMap<>();
        for (int i = 0; i < numCourses; i++) {
            graph.put(i, new ArrayList<Integer>());
        }
        for (int i = 0; i < prerequisites.length; i++) {
            int u = prerequisites[i][0];
            int v = prerequisites[i][1];
            graph.get(v).add(u);
        }
        return graph;
    }
    private Map<Integer, Integer> getIndegree(Map<Integer, ArrayList<Integer>> graph, int numCourses) {
        Map<Integer, Integer> indegree = new HashMap<>();
        for (int i = 0; i < numCourses; i++) {
            indegree.put(i, 0);
        }
        for (int i = 0; i < numCourses; i++) {
            for (Integer neighbor : graph.get(i)) {
                indegree.put(neighbor, indegree.get(neighbor) + 1);
            }
        }
        return indegree;
    }
}
View Code

答案写法:

public class Solution {
    /**
     * @param numCourses a total of n courses
     * @param prerequisites a list of prerequisite pairs
     * @return the course order
     */
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        // Write your code here
        List[] edges = new ArrayList[numCourses];
        int[] degree = new int[numCourses];
        
        for (int i = 0;i < numCourses; i++)
            edges[i] = new ArrayList<Integer>();
            
        for (int i = 0; i < prerequisites.length; i++) {
            degree[prerequisites[i][0]] ++ ;
            edges[prerequisites[i][1]].add(prerequisites[i][0]);
        }

        Queue queue = new LinkedList();
        for(int i = 0; i < degree.length; i++){
            if (degree[i] == 0) {
                queue.add(i);
            }
        }
        
        int count = 0;
        int[] order = new int[numCourses];
        while(!queue.isEmpty()){
            int course = (int)queue.poll();
            order[count] = course;
            count ++;
            int n = edges[course].size();
            for(int i = n - 1; i >= 0 ; i--){
                int pointer = (int)edges[course].get(i);
                degree[pointer]--;
                if (degree[pointer] == 0) {
                    queue.add(pointer);
                }
            }
        }
        
        if (count == numCourses)
            return order;

        return new int[0];
    }
}
View Code

2017-02-09

还缺一道hard题

 5 - 深度优先搜索

18.subsets II

要求:集合中有重复元素

思路:dfs,在I的前提下加入判断条件i != 0 && nums[i] == nums[i - 1] && i != startIndex时continue

    public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] nums) {
        ArrayList<ArrayList<Integer>> results = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return results;
        }
        Arrays.sort(nums);
        dfsHelper(nums, 0, new ArrayList<Integer>(), results);
        return results;
    }
    private void dfsHelper(int[] nums, int startIndex, ArrayList<Integer> subset,
                           ArrayList<ArrayList<Integer>> results) {
        //deep copy
        results.add(new ArrayList<Integer>(subset));
        for (int i = startIndex; i < nums.length; i++) {
            if (i != 0 && nums[i] == nums[i - 1] && i > startIndex) {
                continue;
            }
            subset.add(nums[i]);
            dfsHelper(nums, i + 1, subset, results);
            subset.remove(subset.size() - 1);
        }
    }
View Code

2017-02-10

135.数字组合 combination sum

要求:组合中可能存在重复数,每个数能用多次,求出能相加等于target的集合

思路:dfs,注意条件判断就好,removeDuplicate方法

public class Solution {
    /**
     * @param candidates: A list of integers
     * @param target:An integer
     * @return: A list of lists of integers
     */
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> results = new ArrayList<>();
        if (candidates == null || candidates.length == 0) {
            return results;
        }
        int[] nums = removeDuplicates(candidates);
        dfsHelper(nums, target, 0, new ArrayList<Integer>(), results);
        return results;
    }
    private void dfsHelper(int[] nums, int target, int startIndex,
                           List<Integer> subset,
                           List<List<Integer>> results) {
        if (target == 0) {
            results.add(new ArrayList<Integer>(subset));
        }
        for (int i = startIndex; i < nums.length; i++) {
            if (nums[i] > target) {
                break;
            }
            subset.add(nums[i]);
            dfsHelper(nums, target - nums[i], i, subset, results);
            subset.remove(subset.size() - 1);
        }
    }
    private int[] removeDuplicates(int[] candidates) {
        Arrays.sort(candidates);
        int index = 0;
        for (int i = 1; i < candidates.length; i++) {
            if (candidates[i] != candidates[index]) {
                candidates[++index] = candidates[i];
            }
        }
        int[] nums = new int[index + 1];
        for (int i = 0; i < index + 1; i++) {
            nums[i] = candidates[i];
        }
        return nums;
    }
}
View Code

2017-02-10

153.数字组合 combination sum II

要求:组合中有重复数,每个数只能用一次

思路:与上题区别是这题不能直接去重,因为相同的数也要加入到组合中,但需要像subset II那样排除相同的数调换顺序的重复情况

    public List<List<Integer>> combinationSum2(int[] num, int target) {
        List<List<Integer>> combinations = new ArrayList<>();
        if (num == null || num.length == 0) {
            return combinations;
        }
        Arrays.sort(num);
        dfsHelper(num, target, 0, new ArrayList<Integer>(), combinations);
        return combinations;
    }
    private void dfsHelper(int[] num, int target, int startIndex,
                           List<Integer> combination,
                           List<List<Integer>> combinations) {
        if (target == 0) {
            combinations.add(new ArrayList<Integer>(combination));
            return;
        }
        for (int i = startIndex; i < num.length; i++) {
            if (i != 0 && num[i] == num[i - 1] && i != startIndex) {
                continue;
            }
            if (target < num[i]) {
                break;
            }
            combination.add(num[i]);
            dfsHelper(num, target - num[i], i + 1, combination, combinations);
            combination.remove(combination.size() - 1);
        }
    }
View Code

2017-02-10

136.分隔回文串 Palindrome Partitioning

要求:找出所有把字符串s切割成的全部子字符串都是回文串的方法

思路:仍然是dfs模板,每次加入的是从startIndex切割到当前i的子字符串,并判断其是否回文串(加入isPalindrome方法),递归的出口是切完(startIndex == s.length())

    public List<List<String>> partition(String s) {
        List<List<String>> results = new ArrayList<>();
        if (s == null || s.length() == 0) {
            return results;
        }
        dfsHelper(s, 0, new ArrayList<String>(), results);
        return results;
    }
    private void dfsHelper(String s, int startIndex,
                      List<String> partition,
                      List<List<String>> results) {
        //切完了
        if (startIndex == s.length()) {
            results.add(new ArrayList<String>(partition));
            return;
        }
        for (int i = startIndex; i < s.length(); i++) {
            //切从startIndex到i的一段
            String ss = s.substring(startIndex, i + 1);
            if (!isPalindrome(ss)) {
                continue;
            }
            partition.add(ss);
            dfsHelper(s, i + 1, partition, results);
            partition.remove(partition.size() - 1);
        }
    }
    private boolean isPalindrome(String s) {
        for (int i = 0, j = s.length() - 1; i < j; i++, j--) {
            if (s.charAt(i) != s.charAt(j)) {
                return false;
            }
        }
        return true;
    }
View Code

2017-02-10

15.全排序

要求:如题

思路:dfs,用visited数组标记是否访问过

warn:其实nums == null和nums.length == 0不一样

class Solution {
    /**
     * @param nums: A list of integers.
     * @return: A list of permutations.
     */
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        if (nums == null) {
            return lists;
        }
        if (nums.length == 0) {
            lists.add(new ArrayList<Integer>());
            return lists;
        }
        //sign if it has been visited
        int[] visited = new int[nums.length];
        helper(nums, visited, new ArrayList<Integer>(), lists);
        return lists;
    }
    private void helper(int[] nums, int [] visited,
                        List<Integer> list, List<List<Integer>> lists) {
        if (list.size() == nums.length) {
            lists.add(new ArrayList<Integer>(list));
        }
        for (int i = 0; i < nums.length; i++) {
            if (visited[i] == 1) {
                continue;
            }
            visited[i] = 1;
            list.add(nums[i]);
            helper(nums, visited, list, lists);
            list.remove(list.size() - 1);
            visited[i] = 0;
        }
    }
}
View Code

2017-02-13

16.带重复元素的排列

要求:如题

思路:与上题一样,并加入了subset II的条件

tips:判断时要加入visited[i - 1] == 0才continue

warn:别忘记排序!!

class Solution {
    /**
     * @param nums: A list of integers.
     * @return: A list of unique permutations.
     */
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        if (nums == null) {
            return lists;
        }
        if (nums.length == 0) {
            lists.add(list);
            return lists;
        }
        Arrays.sort(nums);
        int[] visited = new int[nums.length];
        helper(nums, visited, list, lists);
        return lists;
    }
    private void helper(int[] nums, int[] visited,
                        List<Integer> list, List<List<Integer>> lists) {
        if (list.size() == nums.length) {
            lists.add(new ArrayList<Integer>(list));
        }
        for (int i = 0; i < nums.length; i++) {
            if (visited[i] == 1) {
                continue;
            }
            if (i != 0 && nums[i] == nums[i - 1] && visited[i - 1] == 0) {
                continue;
            }
            visited[i] = 1;
            list.add(nums[i]);
            helper(nums, visited, list, lists);
            list.remove(list.size() - 1);
            visited[i] = 0;
        }
    }
}
View Code

2017-02-13

6 - 链表与数组

604.womdow sum

要求:把k长度窗口里的和都算出

思路:(自写AC)two pointers

warn:边界判断

    public int[] winSum(int[] nums, int k) {
        if (nums == null || k == 0 || nums.length < k) {
            return new int[0];
        }
        int[] sums = new int[nums.length - k + 1];
        int sum = 0;
        for (int index = 0; index < k; index++) {
            sum += nums[index];
        }
        sums[0] = sum;
        int i = 0;
        int j = k - 1;
        while (j < nums.length - 1) {
            sum = sum - nums[i++] + nums[++j];
            sums[i] = sum;
        }
        return sums;
    }
View Code

2017-02-14

138.subarray sum

要求:找出和为0的子数组

思路:(自写AC)prefixSum,找出前缀和相同的项就代表此段子数组为0

 写法1:双重循环找:

    public ArrayList<Integer> subarraySum(int[] nums) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        if (nums == null || nums.length == 0) {
            return result;
        }
        int[] prefixSum = new int[nums.length];
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            prefixSum[i] = sum;
        }
        if (prefixSum[nums.length - 1] == 0) {
            result.add(0);
            result.add(nums.length - 1);
            return result;
        }
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (prefixSum[i] == prefixSum[j]) {
                    result.add(i + 1);
                    result.add(j);
                    return result;
                }
            }
        }
        return result;
    }
View Code

写法2:HashMap找(答案)

    public ArrayList<Integer> subarraySum(int[] nums) {
        // write your code here
       
        int len = nums.length;
       
        ArrayList<Integer> ans = new ArrayList<Integer>();
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
       
        map.put(0, -1);
       
        int sum = 0;
        for (int i = 0; i < len; i++) {
            sum += nums[i];
           
            if (map.containsKey(sum)) {
                ans.add(map.get(sum) + 1);
                ans.add(i);
                return ans;
            }
            
            map.put(sum, i);
        }
       
        return ans;
    }
View Code

写法3:二分查找(略)

2017-02-14

41.maximum subarray

要求:找出最大子数组

思路:(自写一次AC)prefixSum数组

warn:注意index从0开始时的情况

    public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return nums[0];
        }
        //prefixSum
        int sum = 0;
        int[] prefixSum = new int[nums.length];
        int result = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            prefixSum[i] = sum;
            result = Math.max(prefixSum[i], result);
        }
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                result = Math.max(prefixSum[j] - prefixSum[i], result);
            }
        }
        return result;
    }
View Code

2017-02-14

139.subarray sum cloest

要求:找出和最接近0的子数组

思路:(自写)prefixSum,每次更新一次,但用两次for循环的话数据量大时会TLE

    public int[] subarraySumClosest(int[] nums) {
        if (nums == null || nums.length == 0) {
            return new int[0];
        }
        int[] res = new int[2];
        int subarraySum = Integer.MAX_VALUE;
        int sum = 0;
        int[] prefixSum = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            prefixSum[i] = sum;
            if (subarraySum > Math.abs(prefixSum[i])) {
                subarraySum = Math.abs(prefixSum[i]);
                res[0] = 0;
                res[1] = i;
            }
        }
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                int currSum = Math.abs(prefixSum[j] - prefixSum[i]);
                if (subarraySum > currSum) {
                    subarraySum = currSum;
                    res[0] = i + 1;
                    res[1] = j;
                }
            }
        }
        return res;
    }
View Code

答案(优化写法):

class Pair {
    int sum;
    int index;
    public Pair(int s, int i) {
        sum = s;
        index = i;
    }
}
public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A list of integers includes the index of the first number 
     *          and the index of the last number
     */
    public int[] subarraySumClosest(int[] nums) {
        int[] res = new int[2];
        if (nums == null || nums.length == 0) {
            return res;
        } 
        
        int len = nums.length;
        if(len == 1) {
            res[0] = res[1] = 0;
            return res;
        }
        Pair[] sums = new Pair[len+1];
        int prev = 0;
        sums[0] = new Pair(0, 0);
        for (int i = 1; i <= len; i++) {
            sums[i] = new Pair(prev + nums[i-1], i);
            prev = sums[i].sum;
        }
        Arrays.sort(sums, new Comparator<Pair>() {
           public int compare(Pair a, Pair b) {
               return a.sum - b.sum;
           } 
        });
        int ans = Integer.MAX_VALUE;
        for (int i = 1; i <= len; i++) {
            
            if (ans > sums[i].sum - sums[i-1].sum) {
                ans = sums[i].sum - sums[i-1].sum;
                int[] temp = new int[]{sums[i].index - 1, sums[i - 1].index - 1};
                Arrays.sort(temp);
                res[0] = temp[0] + 1;
                res[1] = temp[1];
            }
        }
        
        return res;
    }
}
View Code

2017-02-14

165.merge two sorted lists

要求:如题

思路:(自写)dummy node,和sorted array类似

    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode lastNode = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                lastNode.next = l1;
                l1 = l1.next;
            } else {
                lastNode.next = l2;
                l2 = l2.next;
            }
            lastNode = lastNode.next;
        }
        if (l1 != null) {
            lastNode.next = l1;
        }
        if (l2 != null) {
            lastNode.next = l2;
        }
        return dummy.next;
    }
View Code

2017-03-06

599.insert into a cyclic sorted list

要求:如题

思路:(自写但逻辑有错误)根据前后关系找插入的位置

    public ListNode insert(ListNode node, int x) {
        ListNode newNode = new ListNode(x);
        if (node == null) {
            newNode.next = newNode;
            return newNode;
        }
        if (node.next == node) {
            node.next = newNode;
            newNode.next = node;
            return newNode;
        }
        ListNode currNode = node;
        ListNode nextNode = node.next;
        while (currNode.val <= nextNode.val) {
            if (nextNode.next.val <= nextNode.val) {
                if (nextNode.val >= x && currNode.val <= x) {
                    currNode.next = newNode;
                    newNode.next = nextNode;
                    break;
                } else {
                    newNode.next = nextNode.next;
                    nextNode.next = newNode;
                    break;
                }
            } else {
                currNode = nextNode;
                nextNode = nextNode.next;
            }
        }
        return newNode;
    }
View Code

答案:

    public ListNode insert(ListNode node, int x) {
       if (node == null) {
            node = new ListNode(x);
            node.next = node;
            return node;
        }
        //找断点
        ListNode curr = node;
        ListNode prev = null;
        do {
            prev = curr;
            curr = curr.next;
            if (x <= curr.val && x >= prev.val) { 
                break;
            }
            if ((prev.val > curr.val) && (x < curr.val || x > prev.val)) {
                break;
            }
        } while (curr != node);
        //找到插入位置后连接
        ListNode newNode = new ListNode(x);
        newNode.next = curr;
        prev.next = newNode;
        return newNode;
    }
View Code

2017-03-06

102.listed list cycle

要求:判断链表是否有环

思路:(修正答案错误)快慢指针,有环的话会相遇

warn:注意判决条件

    public boolean hasCycle(ListNode head) {  
        if (head == null || head.next == null) {
            return false;
        }
        //快慢指针
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (slow == null || fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
View Code

2017-03-06

98.sort list

要求:把链表排序

思路:(答案)分别用归并和快速排序来完成,

快速:

    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        
        ListNode mid = findMedian(head); // O(n)
        
        ListNode leftDummy = new ListNode(0), leftTail = leftDummy;
        ListNode rightDummy = new ListNode(0), rightTail = rightDummy;
        ListNode middleDummy = new ListNode(0), middleTail = middleDummy;
        while (head != null) {
            if (head.val < mid.val) {
                leftTail.next = head;
                leftTail = head;
            } else if (head.val > mid.val) {
                rightTail.next = head;
                rightTail = head;
            } else {
                middleTail.next = head;
                middleTail = head;
            }
            head = head.next;
        }
        
        leftTail.next = null;
        middleTail.next = null;
        rightTail.next = null;
        
        ListNode left = sortList(leftDummy.next);
        ListNode right = sortList(rightDummy.next);
        
        return concat(left, middleDummy.next, right);
    }
    
    private ListNode findMedian(ListNode head) {
        ListNode slow = head, fast = head.next;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    
    private ListNode concat(ListNode left, ListNode middle, ListNode right) {
        ListNode dummy = new ListNode(0), tail = dummy;
        
        tail.next = left; tail = getTail(tail);
        tail.next = middle; tail = getTail(tail);
        tail.next = right; tail = getTail(tail);
        return dummy.next;
    }
    
    private ListNode getTail(ListNode head) {
        if (head == null) {
           return null;
        } 
       
        while (head.next != null) {
            head = head.next;
        }
        return head;
    }
View Code

归并:

    private ListNode findMiddle(ListNode head) {
        ListNode slow = head, fast = head.next;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }    

    private ListNode merge(ListNode head1, ListNode head2) {
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while (head1 != null && head2 != null) {
            if (head1.val < head2.val) {
                tail.next = head1;
                head1 = head1.next;
            } else {
                tail.next = head2;
                head2 = head2.next;
            }
            tail = tail.next;
        }
        if (head1 != null) {
            tail.next = head1;
        } else {
            tail.next = head2;
        }

        return dummy.next;
    }

    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        ListNode mid = findMiddle(head);

        ListNode right = sortList(mid.next);
        mid.next = null;
        ListNode left = sortList(head);

        return merge(left, right);
    }
View Code

2017-03-07

105.copy list with random pointer

要求:深度复制带有随机指针的链表

思路:(看视频后自写)分三步:1、用next来保存新老节点的对应关系,形成1->1'->2->2'->3->3'的结构 2、复制random指针 3、拆分并各自连回去

warn:注意边界条件

    public RandomListNode copyRandomList(RandomListNode head) {
        if (head == null) {
            return null;
        }
        //three steps
        copyNext(head);
        copyRandom(head);
        return spiltList(head);
    }
    private void copyNext(RandomListNode head) {
        while (head != null) {
            RandomListNode newNode = new RandomListNode(head.label);
            newNode.next = head.next;
            head.next = newNode;
            head = head.next.next;
        }
    }
    private void copyRandom(RandomListNode head) {
        while (head != null) {
            if (head.random != null) {
                head.next.random = head.random.next;
            }
            head = head.next.next;
        }
    }
    private RandomListNode spiltList(RandomListNode head) {
        RandomListNode newHead = head.next;
        while (head != null) {
            RandomListNode temp = head.next;
            head.next = temp.next;
            head = head.next;
            if (temp.next != null) {
                temp.next = temp.next.next;
            }
        }
        return newHead;
    }
View Code

2017-03-08

5.kth largest element(for 65)

要求:如题

思路:(小视频答案)quick select算法,思路和快速排序类似,找标杆把数排成两边

warn:注意每一次递归时候的取值

    public int kthLargestElement(int k, int[] nums) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        return quickSelect(nums, 0, nums.length - 1, k);
    }
    private int quickSelect(int[] nums, int start, int end, int k) {
        if (start == end) {
            return nums[start];
        }
        int i = start, j = end;
        int pivot = nums[(i + j) / 2];
        while (i <= j) {
            while (i <= j && nums[i] > pivot) {
                i++;
            }
            while (i <= j && nums[j] < pivot) {
                j--;
            }
            if (i <= j) {
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                i++;
                j--;
            }
        }
        //三种情况,左中右,i和j中间有可能还有一个数刚好满足
        if (start + k - 1 <= j) {
            return quickSelect(nums, start, j, k);
        }
        if (start + k - 1 >= i) {
            //右边的时候需要去掉左边,所以不是找第k大了
            return quickSelect(nums, i, end, k - (i - start));
        }
        return nums[j + 1];
    }
View Code

2017-03-09

65.median of two sorted array(hard)

 要求:找出两个排序数组的中位数

思路:(看视频后自写)转换成求第k大的数,然后把k = len / 2代入(偶数时需要求len / 2和len / 2 + 1并取平均)时间复杂度推算法,在O(1)时间内,把求第k大的问题简化成第k / 2的问题,也就是对比两个数组k / 2位置上的数,小的那个就把该数组前面的数都丢掉(加入indexA和indexB来实现)

tips:若一个数组不够长取到index + k / 2 - 1个数,则用无穷大代替

warn:当index大于length时,证明第k大个数只存在于另一数组

    public double findMedianSortedArrays(int[] A, int[] B) {
        int len = A.length + B.length;
        if (len % 2 == 0) {
            return (findKth(A, 0, B, 0, len / 2) + findKth(A, 0, B, 0, len / 2 + 1)) / 2.0;
        }
        return findKth(A, 0, B, 0, len / 2 + 1);
    }
    private double findKth(int[] A, int indexA, int[] B, int indexB, int k) {
        if (indexA >= A.length) {
            return B[indexB + k - 1];
        }
        if (indexB >= B.length) {
            return A[indexA + k - 1];
        }
        if (k == 1) {
            return Math.min(A[indexA], B[indexB]);
        }
        //若数组不够长,则赋为无限大
        int keyA = Integer.MAX_VALUE;
        int keyB = Integer.MAX_VALUE;
        if (indexA + k / 2 - 1 < A.length) {
            keyA = A[indexA + k / 2 - 1];
        }
        if (indexB + k / 2 - 1 < B.length) {
            keyB = B[indexB + k / 2 - 1];
        }
        if (keyA < keyB) {
            return findKth(A, indexA + k / 2, B, indexB, k - k / 2);
        } else {
            return findKth(A, indexA, B, indexB + k / 2, k - k / 2);
        }
    }
View Code

2017-03-09

451.Swap Nodes in Pairs

要求:把链表两两交换

思路:建立哨兵节点dummyNode,每次指针停留在要交换节点的上一节点

warn:注意null判断

View Code

2017-09-12

35.Reverse Linked List 翻转链表

要求:如题

思路:创建前向指针(与dummy其实一样)prev,不用交换数字,而是改变链的方向,然后把两个指针逐渐向后移动

View Code

2017-09-12

450.Reverse Nodes in k-Group(hard)

要求:链表中每k个翻转一次,最后不满k个的不要翻转

思路:写一个函数,完成以下几点:1. 记录了每次开始翻转的上一个节点(一开始的时候便是dummy node),这样才可以实现拼接  2.数k次,看是否到结尾 3.翻转

翻转过程中需要记录的节点:1. 开始翻转的第一个节点(翻转后变最后一个点,用于拼接后面) 2. 翻转过程的前后指针prev和curt,临时记录curt.next的temp,因为翻转就是令curt.next = prev,也就是指向前一个节点,然后让prev = curt,curt = temp即把指针后移

public class Solution {
    /*
     * @param head: a ListNode
     * @param k: An integer
     * @return: a ListNode
     */
    public ListNode reverseKGroup(ListNode head, int k) {
        // write your code here
        if (head == null || k <= 1) {
            return head;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        head = dummy;
        
        while (head.next != null) {
            //记录每一次开始节点的上一个位置
            head = reverseNextK(head, k);
        }
        
        return dummy.next;
    }
    private ListNode reverseNextK(ListNode head, int k) {
        ListNode nk = head;
        for (int i = 0; i < k; i++) {
            //数k个,若未数完就出现null,则链表不需要再翻转
            if (nk.next == null) {
                return nk;
            }
            nk = nk.next;
        }
        
        //翻转过程
        //1. head记录的是此次要翻转段的上一个节点,first记录第一个翻转的点
        //   prev,curt为翻转时的前后指针
        ListNode first = head.next;
        ListNode prev = null, curt = first;
        for (int i = 0; i < k; i++) {
            //保存
            ListNode temp = curt.next;
            //反向
            curt.next = prev;
            //指针移动
            prev = curt;
            curt = temp;
        }
        //拼接,第一个翻转的点接下一次需要开始翻转的点,原head接这次翻转最后的点
        first.next = curt;
        head.next = prev;
        //first是下一次的head
        return first;
    }
}
View Code

2017-09-18

96.链表划分

要求:给定一个单链表和数值x,划分链表使得所有小于x的节点排在大于等于x的节点之前。

思路:重新做两个链表 用两个dummy 分别存小于的部分和大于的部分。

public class Solution {
    /*
     * @param head: The first node of linked list
     * @param x: An integer
     * @return: A ListNode
     */
    public ListNode partition(ListNode head, int x) {
        // write your code here
        if (head == null) {
            return null;
        }
        ListNode leftDummy = new ListNode(0);
        ListNode rightDummy = new ListNode(0);
        ListNode left = leftDummy;
        ListNode right = rightDummy;
        while (head != null) {
            if (head.val < x) {
                left.next = head;
                left = left.next;
            } else {
                right.next = head;
                right = right.next;
            }
            head = head.next;
        }
        //记得把最右边的与原先的断开
        right.next = null;
        left.next = rightDummy.next;
        return leftDummy.next;
    }
}
View Code

2017-10-15

547.两数组的交

要求:交中没有重复数

思路:用两个HashSet,第一个Set1把其中一个数组全部放入,Set2放入另一数组时判断自己没有且Set1有才放入,就可以求它们的交,且交中没有重复

    public int[] intersection(int[] nums1, int[] nums2) {
        // write your code here
        if (nums1 == null || nums1.length == 0
            || nums2 == null || nums2.length == 0) {
            return new int[0];        
        }
        Set<Integer> set1 = new HashSet<>();
        for (int num : nums1) {
            if (!set1.contains(num)) {
                set1.add(num);
            }
        }
        Set<Integer> set2 = new HashSet<>();
        for (int num : nums2) {
            if (set1.contains(num) && !set2.contains(num)) {
                set2.add(num);
            }
        }
        int[] result = new int[set2.size()];
        int i = 0;
        for (int num : set2) {
            result[i++] = num;
        }
        return result;
    }
View Code

2018-01-17

548.两数组的交II

要求:交中有重复数,即两数组中若有相同的重复数也放进交中

思路:用HashMap记录其中第一个数组的数和出现次数,用List放入另一数组的数,并在放入前判断Map中是否有该数,且出现次数大于0,放入后把Map中的次数减1

    public int[] intersection(int[] nums1, int[] nums2) {
        // write your code here
        if (nums1 == null || nums1.length == 0
            || nums2 == null || nums2.length == 0) {
            return new int[0];    
        }
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums1) {
            if (map.containsKey(num)) {
                map.put(num, map.get(num) + 1);
            } else {
                map.put(num, 1);
            }
        }
        List<Integer> list = new ArrayList<>();
        for (int num : nums2) {
            if (map.containsKey(num) && map.get(num) > 0) {
                list.add(num);
                map.put(num, map.get(num) - 1);
            }
        }
        int[] result = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            result[i] = list.get(i);
        }
        return result;
    }
View Code

2018-01-17

6.合并排序数组

要求:合并排序数组变成一个新数组

思路:两个数组都还有数时就判断谁小谁先进,其中一个数组越界后就一直放另一个数组

    public int[] mergeSortedArray(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        int[] C = new int[m + n];
        int i = 0, j = 0, k = 0;
        while (i < m && j < n) {
            if (A[i] < B[j]) {
                C[k++] = A[i++];
            } else {
                C[k++] = B[j++];
            }
        }
        while (i < m) {
            C[k++] = A[i++];
        }
        while (j < n) {
            C[k++] = B[j++];
        }
        return C;
    }
View Code

2018-01-17

64.合并排序数组II

要求:在A数组上扩展,其中A后面有预留位置

思路:从后面开始保存就不会覆盖到A前面的数

    public void mergeSortedArray(int[] A, int m, int[] B, int n) {
        // write your code here
        int i = m - 1, j = n - 1, index = m + n - 1;
        while (i >= 0 && j >= 0) {
            if (A[i] >= B[j]) {
                A[index--] = A[i--];
            } else {
                A[index--] = B[j--];
            }
        }
        while (i >= 0) {
            A[index--] = A[i--];
        }
        while (j >= 0) {
            A[index--] = B[j--];
        }
    }
View Code

2018-01-17

7 - Two Pointers

607.two sum - data structure

要求:创造一个数据结构,有添加新元素、查找TwoSum的功能

思路:(自写)开两个全局变量list和map,用map的原因是防止有两个重复数加起来满足TwoSum的target,这时候可以把map的value记录key的个数

warn:记得写构造方法!!!

public class TwoSum {
    private ArrayList<Integer> list;
    private Map<Integer, Integer> map;
    public TwoSum() {
        list = new ArrayList<Integer>();
        map = new HashMap<Integer, Integer>();
    }
    public void add(int number) {
        if (map.containsKey(number)) {
            map.put(number, map.get(number) + 1);
        } else {
            map.put(number, 1);
            list.add(number);
        }
    }

    // Find if there exists any pair of numbers which sum is equal to the value.
    public boolean find(int value) {
        if (list == null || list.size() == 0) {
            return false;
        }
        for (int i = 0; i < list.size(); i++) {
            int num1 = list.get(i), num2 = value - list.get(i);
            if ((num1 == num2 && map.get(num1) > 1) || (num1 != num2 && map.containsKey(num2))) {
                return true;
            }
        }
        return false;
    }
}


// Your TwoSum object will be instantiated and called as such:
// TwoSum twoSum = new TwoSum();
// twoSum.add(number);
// twoSum.find(value);
View Code

2017-03-12

521.remove duplicate numbers in array(去重)

要求:如题

思路1:(自写AC)判断与前一数是否一样,不一样再动index

warn:记得排序才能这样做!!

    public int deduplication(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        Arrays.sort(nums);
        int index = 1;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] != nums[i - 1]) {
                nums[index++] = nums[i];
            }
        }
        return index;
    }
View Code

思路2:hashmap判断是否存在(答案)

    public int deduplication(int[] nums) {
        HashMap<Integer, Boolean> mp = new HashMap<Integer, Boolean>();
        for (int i = 0; i < nums.length; ++i)
            mp.put(nums[i], true);

        int result = 0;
        for (Map.Entry<Integer, Boolean> entry : mp.entrySet())
            nums[result++] = entry.getKey();
        return result;
    }
View Code

2017-03-09

609.two sum - less than or equal to target

要求:如题

思路1:(自写没AC!)同向双指针,即使经过优化后,数据大了还会TLE

    public int twoSum5(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        Arrays.sort(nums);
        int number = 0;
        int end = nums.length;
        for (int i = 0; i < nums.length - 1; i++) {
            if (i >= end) {
                break;
            }
            for (int j = i + 1; j < end; j++) {
                if (nums[i] + nums[j] <= target) {
                    number++;
                } else {
                    end = j;
                    break;
                }
            }
        }
        return number;
    }
View Code

思路2:(答案思路)相向指针,一次过算完中间有几个满足条件的数

    public int twoSum5(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        Arrays.sort(nums);
        int number = 0;
        int i = 0, j = nums.length - 1;
        while (i < j) {
            if (nums[i] + nums[j] > target) {
                j--;
            } else {
                number += j - i;
                i++;
            }
        }
        return number;
    }
View Code

2017-03-10

608.two sum - input array is sorted

要求:如题

思路1:(自写AC)HashMap判断是否存在target - nums[i],但这样没用到排序特性

    public int[] twoSum(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return new int[2];
        }
        Map<Integer, Integer> map = new HashMap<>();
        int[] res = new int[2];
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(target - nums[i])) {
                res[0] = map.get(target - nums[i]) + 1;
                res[1] = i + 1;
                break;
            }
            map.put(nums[i], i);
        }
        return res;
    }
View Code

思路2:(自写AC)two pointers,相向

    public int[] twoSum(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return new int[2];
        }
        int[] res = new int[2];
        int i = 0, j = nums.length - 1;
        while (i < j) {
            int sum = nums[i] + nums[j];
            if (sum < target) {
                i++;
            } else if (sum > target) {
                j--;
            } else {
                res[0] = i + 1;
                res[1] = j + 1;
                break;
            }
        }
        return res;
    }
View Code

2017-03-10

587.two sum - unique pairs

要求:求所有和为target的数量

思路:(自写差点一次AC)还是相向指针,没AC的原因是if(target == sum)时忘记判断i < j,导致多了一个

    public int twoSum6(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        Arrays.sort(nums);
        int number = 0;
        int i = 0, j = nums.length - 1;
        while (i < j) {
            while (j != nums.length - 1 && i < j && nums[j] == nums[j + 1]) {
                j--;
            }
            while (i != 0 && i < j && nums[i] == nums[i - 1]) {
                i++;
            }
            int sum = nums[i] + nums[j];
            if (i < j && sum == target) {
                number++;
                i++;
                j--;
            } else if (sum < target) {
                i++;
            } else {
                j--;
            }
        }
        return number;
    }
View Code

2017-03-10

533.two sum - closest to target

要求:求最接近的差

思路:(自写AC)加入diff变量,仍是套用相向指针模板

    public int twoSumClosest(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return -1;
        }
        Arrays.sort(nums);
        int i = 0, j = nums.length - 1;
        int diff = Integer.MAX_VALUE;
        while (i < j) {
            int sum = nums[i] + nums[j];
            diff = Math.min(diff, Math.abs(sum - target));
            if (target == sum) {
                return 0;
            } else if (target < sum) {
                j--;
            } else {
                i++;
            }
        }
        return diff;
    }
View Code

2017-03-10

148.sort colors

要求:把0,1,2排序

思路:(答案)三个指针!!添加一个中间指针i。左边交换时i和left同时动,右边交换时只有right动,不交换i自己动

warn:判断条件是i <= right

    public void sortColors(int[] nums) {
        if (nums == null || nums.length < 2) {
            return;
        }
        int i = 0, left = 0, right = nums.length - 1;
        while (i <= right) {
            if (nums[i] == 0) {
                swap(nums, left, i);
                i++;
                left++;
            } else if (nums[i] == 1) {
                i++;
            } else {
                swap(nums, right, i);
                right--;
            }
        }
    }
    private void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
View Code

2017-03-10

143.sort colors II

 要求:有k种颜色,对n个对象进行排序

思路:(答案)先推出时间复杂度为nlogk,然后对k种颜色使用快排思想,称为rainbowSort彩虹排序

    public void sortColors2(int[] colors, int k) {
        if (colors == null || colors.length == 0) {
            return;
        }
        rainbowSort(colors, 0, colors.length - 1, 1, k);
    }
    
    public void rainbowSort(int[] colors,
                            int left,
                            int right,
                            int colorFrom,
                            int colorTo) {
        if (colorFrom == colorTo) {
            return;
        }
        
        if (left >= right) {
            return;
        }
        
        int colorMid = (colorFrom + colorTo) / 2;
        int l = left, r = right;
        while (l <= r) {
            while (l <= r && colors[l] <= colorMid) {
                l++;
            }
            while (l <= r && colors[r] > colorMid) {
                r--;
            }
            if (l <= r) {
                int temp = colors[l];
                colors[l] = colors[r];
                colors[r] = temp;
                
                l++;
                r--;
            }
        }
        
        rainbowSort(colors, left, r, colorFrom, colorMid);
        rainbowSort(colors, l, right, colorMid + 1, colorTo);
    }
View Code

2017-03-12

57.3Sum

要求:存在重复数,相加为0

思路1:(自写AC)化为two sum,用set去重答案

    public ArrayList<ArrayList<Integer>> threeSum(int[] numbers) {
        ArrayList<ArrayList<Integer>> results = new ArrayList<>();
        Set<ArrayList<Integer>> set = new HashSet<>();
        Arrays.sort(numbers);
        for (int i = 0; i < numbers.length - 2; i++) {
            int left = i + 1, right = numbers.length - 1;
            while (left < right) {
                int sum = numbers[left] + numbers[right];
                if (sum == -numbers[i]) {
                    ArrayList<Integer> list = new ArrayList<>();
                    list.add(numbers[i]);
                    list.add(numbers[left]);
                    list.add(numbers[right]);
                    if (!set.contains(list)) {
                        results.add(list);
                        set.add(list);
                    }
                    left++;
                    right--;
                } else if (sum < -numbers[i]) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        return results;
    }
View Code

思路2:(答案)排序后用number[i] == number[i - 1]去重,更省空间

    public ArrayList<ArrayList<Integer>> threeSum(int[] nums) {
        ArrayList<ArrayList<Integer>> results = new ArrayList<>();
        
        if (nums == null || nums.length < 3) {
            return results;
        }
        
        Arrays.sort(nums);

        for (int i = 0; i < nums.length - 2; i++) {
            // skip duplicate triples with the same first numebr
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            int left = i + 1, right = nums.length - 1;
            int target = -nums[i];
            
            twoSum(nums, left, right, target, results);
        }
        
        return results;
    }
    
    public void twoSum(int[] nums,
                       int left,
                       int right,
                       int target,
                       ArrayList<ArrayList<Integer>> results) {
        while (left < right) {
            if (nums[left] + nums[right] == target) {
                ArrayList<Integer> triple = new ArrayList<>();
                triple.add(-target);
                triple.add(nums[left]);
                triple.add(nums[right]);
                results.add(triple);
                
                left++;
                right--;
                // skip duplicate pairs with the same left
                while (left < right && nums[left] == nums[left - 1]) {
                    left++;
                }
                // skip duplicate pairs with the same right
                while (left < right && nums[right] == nums[right + 1]) {
                    right--;
                }
            } else if (nums[left] + nums[right] < target) {
                left++;
            } else {
                right--;
            }
        }
    }
View Code

2017-03-12

31.partition array

要求:以k为标准把数组分成两边

思路:(自写但有bug)quick select思想,相向指针把小于的放一边大于放另一边

warn:注意边界条件为left <= right才对!!

    public int partitionArray(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            while (left <= right && nums[left] < k) {
                left++;
            }
            while (left <= right && nums[right] >= k) {
                right--;
            }
            if (left <= right) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
                left++;
                right--;
            }
        }
        return left;
    }
View Code

2017-03-12

 604.滑动窗口内数的和

 要求:给定大小为n的数组和大小为k的滑动窗口,输出从数组开头滑动每一个时刻的窗口内数的和

思路:先求出开始第一个窗口的和sum,然后每移动一次减去头加上尾的数

    public int[] winSum(int[] nums, int k) {
        if (nums == null || k == 0 || nums.length < k) {
            return new int[0];
        }
        int[] sums = new int[nums.length - k + 1];
        int sum = 0;
        for (int index = 0; index < k; index++) {
            sum += nums[index];
        }
        sums[0] = sum;
        int i = 0;
        int j = k - 1;
        while (j < nums.length - 1) {
            sum = sum - nums[i++] + nums[++j];
            sums[i] = sum;
        }
        return sums;
    }
View Code

2018-01-17

539.移动零

要求:把数组中的0都移到尾部,其他数保持原有顺序

思路:首先把不是0的数按顺序赋值到数组前面,然后再在数组剩下的部分补充0

    public void moveZeroes(int[] nums) {
        // write your code here
        if (nums == null || nums.length == 0) {
            return;
        }
        int index = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                nums[index++] = nums[i];
            }
        }
        while (index < nums.length) {
            nums[index++] = 0;
        }
    }
View Code

2018-01-17

415.有效回文串

要求:只包含数字和字母,忽略大小写

思路:首尾指针开始先判断是不是数字或者字母,若是则统一转成小写(或者大写)来比较

    public boolean isPalindrome(String s) {
        // write your code here
        if (s == null || s.length() == 0) {
            return true;
        }
        int start = 0;
        int end = s.length() - 1;
        while (start < end) {
            while (start < s.length() && !isValid(s.charAt(start))) {
                start++;
            }
            while (end >= 0 && !isValid(s.charAt(end))) {
                end--;
            }
            if (start < s.length() && end >= 0 && Character.toLowerCase(s.charAt(start))
                != Character.toLowerCase(s.charAt(end))) {
                return false;    
            }
            start++;
            end--;
        }
        return true;
    }
    private boolean isValid(char c) {
        return Character.isLetter(c) || Character.isDigit(c);
    }
View Code

2018-01-17

56.两数之和

要求:在数组中找出两数的和等于指定数target,返回数组对应的下标

思路:用HashMap的key装数组的值,用于判断是否存在两数之和等于target,用value装下标

    public int[] twoSum(int[] numbers, int target) {
        // write your code here
        if (numbers == null || numbers.length == 0) {
            return new int[]{0, 0};
        }
        Map<Integer, Integer> map = new HashMap<>();
        int[] result = new int[2];
        for (int i = 0; i < numbers.length; i++) {
            if (map.containsKey(target - numbers[i])) {
                result[0] = map.get(target - numbers[i]);
                result[1] = i + 1;
                break;
            }
            map.put(numbers[i], i + 1);
        }
        return result;
    }
View Code

2018-01-17

 8 - 哈希表与堆

128.hash function

要求:按照题目给出的公式算

思路:(自写一直不成功,不知原因)最重要是字符转ascii码

    public int hashCode(char[] key, int HASH_SIZE) {
        if (key == null || key.length == 0) {
            return 0;
        }
        long ans = 0;
        for(int i = 0; i < key.length;i++) {
            ans = (ans * 33 + (int)(key[i])) % HASH_SIZE; 
        }
        return (int)ans;
    }
View Code

2017-03-13

129.rehashing

要求:把哈希表复制一遍并增大一倍size

思路:(自写时没有考虑好ListNode[]中存的到底是实体还是指针,其实是指针)deep copy时记住若原本的hashTable[i] !=null,它仍可能有下一项,而且复制过去的newTable[i],它不一定是第一次用i这个位置,若不是的时候,首先要用dummy指针获得链表最后的位置

Notice:(题目自带)if you directly calculate -4 % 3 you will get -1. You can use function: a % b = (a % b + b) % b to make it is a non negative integer

    public ListNode[] rehashing(ListNode[] hashTable) {
        // write your code here
        if (hashTable.length <= 0) {
            return hashTable;
        }
        int newcapacity = 2 * hashTable.length;
        ListNode[] newTable = new ListNode[newcapacity];
        for (int i = 0; i < hashTable.length; i++) {
            while (hashTable[i] != null) {
                int newindex
                 = (hashTable[i].val % newcapacity + newcapacity) % newcapacity;
                if (newTable[newindex] == null) {
                    newTable[newindex] = new ListNode(hashTable[i].val);
                   // newTable[newindex].next = null;
                } else {
                    ListNode dummy = newTable[newindex];
                    while (dummy.next != null) {
                        dummy = dummy.next;
                    }
                    dummy.next = new ListNode(hashTable[i].val);
                }
                hashTable[i] = hashTable[i].next;
            }
        }
        return newTable;
    }
View Code

2017-03-16

134.LRU cache(hard)

要求:实现一个数据结构,使满足1. get方法,把key对应的value取出,并把key放大最后(代表最近使用,也就是LRU) 2. set方法,若存在key则更新value,并把key放到最后,若超过此数据结构的capacity,要把头部的数据删掉,再在末尾插入

思路:(答案+自己注释)要点 1. 定义双向链表node 2.LRU方案需要head、tail节点支持后面的操作,并用hashmap来链接key和node的位置(这样可以通过O1的时间找到node),自己包含一个最大长度capacity 3.get方法中记得判断有无,有的情况下记得把原来key的位置断开并连接前后,然后把key放到结尾 4.set方法中判断存不存在key的时候要用get方法判断(不能直接用map判断,因为用get方法在存在key时就可以顺便完成了断开中间并移到末尾的操作),不存在的时候则考虑有没有超过capacity,超过就先去掉头部再在末尾插入

详细看注释:

public class Solution {
    //双向链表
    private class Node {
        Node prev;
        Node next;
        int key;
        int value;
        //内部类的构造方法
        public Node(int key, int value) {
            this.key = key;
            this.value = value;
            this.prev = null;
            this.next = null;
        }
    }
    //在LRU方案中 需要头尾节点来辅助更改 不存储真正的数据
    //key与node在map中匹配 这样可以通过key找到node
    private int capacity;
    private Map<Integer, Node> map = new HashMap<>();
    private Node head = new Node(-1, -1);
    private Node tail = new Node(-1, -1);
    // @param capacity, an integer
    //LRU cache的构造函数
    public Solution(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.prev = head;
    }

    // @return an integer
    //1. 判断有无
    //2. 有的话取出它的value 并移到末尾(表示最近使用过)
    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        //用hashmap定位node在哪 然后移除它
        Node current = map.get(key);
        current.prev.next = current.next;
        current.next.prev = current.prev;
        //把它移到末尾
        moveToTail(current);
        return map.get(key).value;
    }

    // @param key, an integer
    // @param value, an integer
    // @return nothing
    //1. 若已存在key 则更新它的value
    //2. 若到达LRU cache的最大capacity 将头部删除并插入在最后
    public void set(int key, int value) {
        //存在时更新value 并通过get方法讲key移到最后!!!
        if (get(key) != -1) {
            map.get(key).value = value;
            return;
        }
        if (map.size() == capacity) {
            map.remove(head.next.key);
            head.next = head.next.next;
            head.next.prev = head;
        }
        Node newNode = new Node(key, value);
        map.put(key, newNode);
        moveToTail(newNode);
    }
    private void moveToTail(Node node) {
        node.prev = tail.prev;
        tail.prev = node;
        node.prev.next = node;
        node.next = tail;
    }
}
View Code

2017-03-16

544.top k largest numbers

要求:把前k大的数输出

思路:(自写,注意写法)PriorityQueue最基本用法,java中默认的是实现了minheap的优先队列,而求最大的数用的是最大堆,注意构造PQ时候的comparator写法,这样可以实现最大堆,而队列长就是k

    public int[] topk(int[] nums, int k) {
        PriorityQueue<Integer> minheap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                if (o1 < o2) {
                    return 1;
                } else if (o1 > o2) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
        for (int i : nums) {
            minheap.add(i);
        }
        int[] res = new int[k];
        for (int i = 0; i < res.length; i++) {
            res[i] = minheap.poll();
        }
        return res;
    }
View Code

2017-03-16

606.kth largest element II

要求:把第k大数输出就行

思路1:(自写AC)同上,这次只需要输出一个数

    public int kthLargestElement2(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k == 0) {
            return 0;
        }
        PriorityQueue<Integer> minheap = new PriorityQueue<>(k, new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                if (o1 < o2) {
                    return 1;
                } else if (o1 > o2) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
        for (int i : nums) {
            minheap.add(i);
        }
        int res = 0;
        for (int i = 0; i < k; i++) {
            if (i == k - 1) {
                res = minheap.peek();
            }
            minheap.poll();
        }
        return res;
    }
View Code

思路2:也可以用quickselect来做

2017-03-17

612.k closest point

要求:求到origin坐标最近的k个点

思路:(答案)还是PQ的应用,不过仍不知道PQ里面的comparator到底怎么设计,答案中设计的是以diff为参考值的最大堆!!

warn:不知道怎么搞的,明明限制了pq的长度是k,但超过k时候仍然不会自动丢弃,而要有pq.size() > k时poll(),而且不把origin点设成全局变量会报错...

public class Solution {
    /**
     * @param points a list of points
     * @param origin a point
     * @param k an integer
     * @return the k closest points
     */
    private Point global_origin = null;
    public Point[] kClosest(Point[] points, Point origin, int k) {
        global_origin = origin;
        PriorityQueue<Point> pq = new PriorityQueue<>(k, new Comparator<Point>() {
            public int compare(Point a, Point b) {
                int diff = getDistance(b, global_origin) - getDistance(a, global_origin);
                if (diff == 0) {
                    diff = b.x - a.x;
                }
                if (diff == 0) {
                    diff = b.y - a.y;
                }
                return diff;
            }
        });
        for (Point p : points) {
            pq.add(p);
            //最大堆 超过长度的poll掉
            if (pq.size() > k) {
                pq.poll();
            }
        }
        Point[] res = new Point[k];
        while (!pq.isEmpty()) {
            res[--k] = pq.poll();
        }
        return res;
    }
    private int getDistance(Point a, Point b) {
        return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
    }
}
View Code

2017-03-17

613.high five

要求:找出学生id对应的前五位成绩,求平均后放到map中与id对应起来

思路:(自写答案不对?)用之前的思路,pq判断前五大成绩,然后求平均

public class Solution {
    /**
     * @param results a list of <student_id, score>
     * @return find the average of 5 highest scores for each person
     * Map<Integer, Double> (student_id, average_score)
     */
    public Map<Integer, Double> highFive(Record[] results) {
        if (results == null || results.length == 0) {
            return new HashMap<Integer, Double>();
        }
        Map<Integer, PriorityQueue<Integer>> map = new HashMap<>();
        for (int i = 0; i < results.length; i++) {
            if (!map.containsKey(results[i].id)) {
                map.put(results[i].id, new PriorityQueue<Integer>(
                5, new Comparator<Integer>() {
                    public int compare(Integer o1, Integer o2) {
                        if (o1 < o2) {
                            return 1;
                        } else if (o1 > o2) {
                            return -1;
                        } else {
                            return 0;
                        }
                    }
                }));
            } else {
                map.get(results[i].id).add(results[i].score);
            }
        }
        Map<Integer, Double> res = new HashMap<>();
        for (int i = 0; i < results.length; i++) {
            if (!res.containsKey(results[i].id)) {
                double average = getAverage(map.get(results[i].id));
                res.put(results[i].id, average);
            }
        }
        return res;
    }
    private double getAverage(PriorityQueue<Integer> pq) {
        double sum = 0;
        while (!pq.isEmpty()) {
            double score = pq.poll();
            sum += score;
        }
        return sum / 5.0;
    }
}
View Code

答案:直接用ArrayList来存成绩,因为只取五项比较少,所以可以通过循环来获得最小的来和目前的比较,比最小的大就存进去(其实这也是堆的原理,不过如果取的项比较多,这种方法应该不行)

public class Solution {
    /**
     * @param results a list of <student_id, score>
     * @return find the average of 5 highest scores for each person
     * Map<Integer, Double> (student_id, average_score)
     */
    public Map<Integer, Double> highFive(Record[] results) {
        Map<Integer, Double> answer = new HashMap<Integer, Double>();
        Map<Integer, List<Integer>> hash = new HashMap<Integer, List<Integer>>();

        for (Record r : results) {
            if (!hash.containsKey(r.id)){
                hash.put(r.id, new ArrayList<Integer>());
            }

            if (hash.get(r.id).size() < 5) {
                hash.get(r.id).add(r.score);
            } else {
                int index = 0;
                for (int i = 1; i < 5; ++i)
                    if (hash.get(r.id).get(i) < hash.get(r.id).get(index))
                        index = i;
                if (hash.get(r.id).get(index) < r.score)
                    hash.get(r.id).set(index, r.score);
            }
        }

        for (Map.Entry<Integer, List<Integer>> entry : hash.entrySet()) {
            int id = entry.getKey();
            List<Integer> scores = entry.getValue();
            double average = 0;
            for (int i = 0; i < 5; ++i)
                average += scores.get(i);
            average /= 5.0;
            answer.put(id, average);
        }
        return answer;
    }
}
View Code

2017-03-17

104.merge k sorted lists

要求:合并k个有序链表

思路:(看答案自写)1. 把所有链表头放进heap 2. 把当前链表头的next放进去heap(这样又自动排序了)有点像BFS的思想

自写时把链表头放进heap时忘记判断lists.get(i) != null

public class Solution {
    /**
     * @param lists: a list of ListNode
     * @return: The head of one sorted list.
     */
    private Comparator<ListNode> ListNodeComparator = new Comparator<ListNode>() {
        public int compare(ListNode left, ListNode right) {
            return left.val - right.val;
        }
    };
    public ListNode mergeKLists(List<ListNode> lists) {  
        if (lists == null || lists.size() == 0) {
            return null;
        }
        Queue<ListNode> heap = new PriorityQueue<>(lists.size(), ListNodeComparator);
        //把所有链表头先放入heap
        for (int i = 0; i < lists.size(); i++) {
            if (lists.get(i) != null) {
                heap.add(lists.get(i));
            }
        }
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while (!heap.isEmpty()) {
            ListNode current = heap.poll();
            tail.next = current;
            tail = current;
            //若当前还有next 则添加到heap中继续排序
            if (current.next != null) {
                heap.add(current.next);
            }
        }
        return dummy.next;
    }
}
View Code

还可以用分治法来做

2017-03-17

4.丑数II

要求:找出只含素因子2,3,5的第n小的数,符合条件的数为1,2,3,4,5,6,8,9,10

思路:用三个指针来判断

    public int nthUglyNumber(int n){
        List<Integer> uglys = new ArrayList<Integer>(); //创建整形动态数组;
        uglys.add(1); //把特殊值1首先加入;
        
        int p2 = 0, p3 = 0, p5 = 0; //分别代表了与2、3、5相乘元素的序号,相当于指针;
        
        //用前面各个位置的数与2,3,5相乘直到比上一个数大,并获得相应位置;
        for (int i = 0; i <= n - 2; i++){
            int lastNumber = uglys.get(i); 
            //获取数组中上一个元素,第n个数的上一个对应下标为n-2;
            while (uglys.get(p2) * 2 <= lastNumber) p2++;
            while (uglys.get(p3) * 3 <= lastNumber) p3++;
            while (uglys.get(p5) * 5 <= lastNumber) p5++;
            
            //对比p2,p3,p5位置上分别与2,3,5相乘的结果,最小值添加为下一元素;
            uglys.add(Math.min(Math.min(uglys.get(p2) * 2, uglys.get(p3) * 3), uglys.get(p5) * 5));
        }
        return uglys.get(n - 1);
    }
View Code

2018-01-17

594.strStr II

要求:用O(m + n)的时间复杂度完成查找字符串

思路:(小视频)Rabin Karp算法,利用hashcode来判断,若相同的时候才进行每一位的比较

warn:注意下标

public class Solution {
    //hashcode
    public final int BASE = 1000000;
    /**
     * @param source a source string
     * @param target a target string
     * @return an integer as index
     */
    public int strStr2(String source, String target) {
        if (source == null || target == null) {
            return -1;
        }
        int m = target.length();
        if (m == 0) {
            return 0;
        }
        // count 31 ^ m
        int power = 1;
        for (int i = 0; i < m; i++) {
            power = (power * 31) % BASE;
        }
        // target hashcode
        int targetCode = 0;
        for (int i = 0; i < m; i++) {
            targetCode = (targetCode * 31 + target.charAt(i)) % BASE;
        }
        // substring hashcode
        int substrCode = 0;
        for (int i = 0; i < source.length(); i++) {
            substrCode = (substrCode * 31 + source.charAt(i)) % BASE;
            if (i < m - 1) {
                continue;
            }
            // 超过m长度后减去头字符的hashcode
            if (i >= m) {
                substrCode = substrCode - (power * source.charAt(i - m)) % BASE;
                if (substrCode < 0) {
                    substrCode += BASE;
                }
            }
            if (substrCode == targetCode) {
                if (source.substring(i - m + 1, i + 1).equals(target)) {
                    return i - m + 1;
                }
            }
        }
        return -1;
    }
}
View Code

2017-03-22

134.LRU缓存策略(hard

要求:为最近最小使用(LRU)缓存策略设计一个数据结构,支持get获取数据和set写入数据

get(key):如果缓存存在key,则获取它的值,否则返回-1

set(key, value):如果key没在缓存中则直接写入;当缓存达到上限,在写入数据前删除最近最少使用的数据来腾出空间

答案:

    //双向链表
    private class Node {
        Node prev;
        Node next;
        int key;
        int value;
        //内部类的构造方法
        public Node(int key, int value) {
            this.key = key;
            this.value = value;
            this.prev = null;
            this.next = null;
        }
    }
    //在LRU方案中 需要头尾节点来辅助更改 不存储真正的数据
    //key与node在map中匹配 这样可以通过key找到node
    private int capacity;
    private Map<Integer, Node> map = new HashMap<>();
    private Node head = new Node(-1, -1);
    private Node tail = new Node(-1, -1);
    // @param capacity, an integer
    //LRU cache的构造函数
    public Solution(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.prev = head;
    }

    // @return an integer
    //1. 判断有无
    //2. 有的话取出它的value 并移到末尾(表示最近使用过)
    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        //用hashmap定位node在哪 然后移除它
        Node current = map.get(key);
        current.prev.next = current.next;
        current.next.prev = current.prev;
        //把它移到末尾
        moveToTail(current);
        return map.get(key).value;
    }

    // @param key, an integer
    // @param value, an integer
    // @return nothing
    //1. 若已存在key 则更新它的value
    //2. 若到达LRU cache的最大capacity 将头部删除并插入在最后
    public void set(int key, int value) {
        //存在时更新value
        if (get(key) != -1) {
            map.get(key).value = value;
            return;
        }
        if (map.size() == capacity) {
            map.remove(head.next.key);
            head.next = head.next.next;
            head.next.prev = head;
        }
        Node newNode = new Node(key, value);
        map.put(key, newNode);
        moveToTail(newNode);
    }
    private void moveToTail(Node node) {
        node.prev = tail.prev;
        tail.prev = node;
        node.prev.next = node;
        node.next = tail;
    }
View Code

2018-01-17

原文地址:https://www.cnblogs.com/kinghey-java-ljx/p/6290494.html