Jerry's Blog

Recording what I learned everyday

View on GitHub


3 November 2019

LeetCode(57) -- 64, 1099,

by Jerry Zhang

P64. Minimum Path Sum (Medium)

一个整数二维数组。找出从左上角到右下角所有数的和最小的一条路径。

我的思路

典型的动态规划。要点是一定不要从后往前递归,那样会有非常庞大的重复计算。要从左上向右下层层推进,每一步都已经算好了左边和上面的最小值,找到一个相对较小的,再加上本身,就是到达当前点的最小值。

我的代码

class Solution {
    public int minPathSum(int[][] grid) {
        int[][] memo = new int[grid.length][grid[0].length];
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[i].length; j++) {
                if (i == 0 && j == 0) {
                    memo[i][j] = grid[i][j];
                } else if (i == 0) {
                    memo[i][j] = memo[i][j-1] + grid[i][j];
                } else if (j == 0) {
                    memo[i][j] = memo[i-1][j] + grid[i][j];
                } else {
                    memo[i][j] = Math.min(memo[i-1][j], memo[i][j-1]) + grid[i][j];
                }
            }
        }
        return memo[grid.length-1][grid[0].length-1];
    }
}

90%

最优解

class Solution {
    public int minPathSum(int[][] grid) {
        if (grid == null || grid.length == 0)
            return 0;
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        return dfs(grid, dp, m - 1, n - 1);
    }

    private int dfs(int[][] grid, int[][] dp, int m, int n) {
        if (m < 0 || n < 0)
            return Integer.MAX_VALUE;
        if (m == 0 && n == 0)
            return grid[0][0];

        if (dp[m][n] == 0)
            dp[m][n] = grid[m][n]
                    + Math.min(dfs(grid, dp, m - 1, n), dfs(grid, dp, m, n - 1));

        return dp[m][n];
    }
}

如果越界的话,就直接用最大的整数值挡在外面了。如果需要用到的数还没算过,就去算一下。时间复杂度应该和我是一样的。

P1099. Two Sum Less Than K (Easy))

在一个数组中,找出两个数的和小于K的最大的可能的值。

我的思路

一开始的思路:把所有数都存到一个hash数组里,然后每遇到一个数,用K减去这个数,从那个位置开始向下找,找到第一个数记下来。因为数的范围是1-1000,所以每次最多需要找1000次,而一共有100个数。所以这种办法非常慢。

我的代码

class Solution {
    public int twoSumLessThanK(int[] A, int K) {
        boolean[] set = new boolean[1000];
        for (int i : A) {
            set[i - 1] = true;
        }
        int s = -1;
        for (int i = 0; i < A.length; i++) {
            int j = K - A[i] - 1;
            while (j > 0) {
                if (j <= 1000 && j != A[i] && set[j-1]) {
                    s = Math.max(s, A[i] + j);
                    break;
                }
                j--;
            }
        }
        return s;
    }
}

12% 不要用这个方法,非常不好。

最优解

public class E_1099_TwoSumLessThanK {
    public int twoSumLessThanK(int[] A, int K) {
        Arrays.sort(A);
        int i = 0;
        int j = A.length - 1;
        int max = -1;
        while (i < j) {
            int sum = A[i] + A[j];
            if (sum < K) {
                max = Math.max(max, sum);
                i++;
            } else {
                j--;
            }
        }
        return max;
    }
}

先把数组排序。从两侧开始找。如果想让两个数的和最大,优先找最大的那个数,看有没有比较小的数能跟它匹配上。从两侧往中间“挤”的好处是,每次减小最大值是,前面所有的最小值都不需要再算了,因为比这个最大值更大的数都试过了,减小之后肯定更小,也就不用再试了。

P532. K-diff Pairs in an Array (Easy)

问一个数组里,有多少个不同的pair绝对值的差为k。

Input: [3, 1, 4, 1, 5], k = 2
Output: 2
Explanation: There are two 2-diff pairs in the array, (1, 3) and (3, 5).
Although we have two 1s in the input, we should only return the number of unique pairs.

我的思路

当k等于0时,其实相当于问这个数组里有哪些数发生了重复;当k不等于0时,就检查一下以前出现过的数中,有没有跟当前这个数的绝对值差k的。

我的代码

class Solution {
    public int findPairs(int[] nums, int k) {
        if (k < 0) {
            return 0;
        }
        HashSet<Integer> set = new HashSet<>();
        HashSet<Integer> duplicate = new HashSet<>();
        int count = 0;
        for (int num : nums) {
            if (set.contains(num)) {
                duplicate.add(num);
            } else {
                if (set.contains(num + k)) {
                    count++;
                }
                if (set.contains(num - k)) {
                    count++;
                }
            }
            set.add(num);
        }
        if (k == 0) {
            return duplicate.size();
        }
        return count;
    }
}

80%

最优解

class Solution {
    public int findPairs(int[] nums, int k) {
        if (nums.length <=1 || k < 0) return 0;
        Arrays.sort(nums);
        int left = 0, right = 1, count =0;
        while (right < nums.length) {
            if (nums[right] - nums[left] > k)
                left++;
            else if (nums[right] - nums[left] < k || left == right)
                right++;
            else {
                count++;
                left++;
                right++;
                while(right < nums.length && nums[right] == nums[right - 1])
                    right++;
            }
        }
        return count;
    }
}

这个方法很妙,但一般情况下想不到。先排序,然后把两个指针前后调整,使它们的差为k。

tags: LeetCode