zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    调试某狐木马驱动被杀后系统卡死开机
    情景剧:C/C++中的未定义行为(undefined behavior)
    汇编概念辨析(Intel/AT&T syntax、GAS、NASM)
    软考准考证打印设置(IE1909)
    基于redis的分布式锁 RedissonLock解锁异常解决
    深入理解synchronized
    单利模式
    归并排序
    旧电脑硬盘回收
    萤石、乐橙、3D
  • 原文地址:https://www.cnblogs.com/kinghey-java-ljx/p/6290494.html
Copyright © 2011-2022 走看看