Jerry's Blog

Recording what I learned everyday

View on GitHub


17 September 2019

LeetCode(10) -- 448, 453, 455

by Jerry Zhang

P448. Find All Numbers Disappeared in an Array (Easy)

给一个数组长度为n,找出所有1到n之间未出现的数。要求不增加新内存,并且O(n)

Input:
[4,3,2,7,8,2,3,1]

Output:
[5,6]

我的思路

如果允许新加内存空间,直接新建一个布尔数组存一下每个数是否出现过即可。不新加内存我暂时想不出。

我的代码

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        boolean[] bool = new boolean[nums.length];
        for (int i = 0; i < nums.length; i++) {
            bool[nums[i]-1] = true;
        }
        List<Integer> integers = new ArrayList<>();
        for (int i = 0; i < bool.length; i++) {
            if (!bool[i]) {
                integers.add(i + 1);
            }
        }
        return integers;
    }
}

99%

最优解

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {

        int[] arr = new int[nums.length+1];

        for(int i=0;i<nums.length;i++) {
            arr[nums[i]]++;
        }

        List<Integer> list=new ArrayList<>();

        for(int i=1;i<arr.length;i++) {
            if(arr[i]==0) {
              list.add(i);
            }
        }

        return list;
    }
}

同样新开了一个空间。基本思路差不多,没什么特别的。

讨论区

public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> list = new ArrayList<Integer>();
        int value = 0, index = 1, len = nums.length;
        for( int i = 0; i < len; i++ )
            value |= (1 << (nums[i]-1));

        while( value > 0 || len > 0) {
            if ((value & 1) == 0)
                list.add(index);
            index++;
            len--;
            value >>= 1;
        }
        return list;

这个解法非常新颖。他用二进制每个位置上的1代表这个数出现过,用0代表没出现过。实际上相当于把二进制当作一个boolean数组来使用。如果出现了1,那二进制表示就是“1”,如果出现了2,那二进制表示就是“11”,如果跳过了3,而出现了两次4,那二进制表示就是“1011”。总之,这个二进制的数,从右数,第几位是1,就代表那个数出现过。比如从右数第二位是1,就代表2出现过。

最后用while循环时,记录一个长度len,然后从右向左依次检查该位置上是否是1。如果是1,就把这个数添加进List。

P453. Minimum Moves to Equal Array Elements (Easy)

给一个长度为n的数组,可以进行如下操作:对其中的n-1个数分别增加1。问:进行多少次这样的操作,可以使用数组内所有的数都相等?

Input:
[1,2,3]

Output:
3

Explanation:
Only three moves are needed (remember each move increments two elements):

[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

我的思路

每次把所有的n-1个数都加1,实际上相当于把最大的数减1。因为最终目标是让所有数都相等,所有这两种操作实际上是等价的。那就把所有的数跟最小的数做差,然后把它们加起来就是要返回的结果。

实现的时候,我不想整个数组跑两趟。先假定第一个数就是最小值,然后后面的数如果比它大,就累加上它们的差;如果比它小,就把所有的数都更新,全部累加上它们的差,并更新最小值min。

我的代码

public class E_453_MinimumMovesToEqualArrayElements {
    public int minMoves(int[] nums) {
        int min = nums[0];
        int res = 0;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] > min) {
                res += nums[i] - min;
            } else if (nums[i] < min) {
                res += (min - nums[i]) * i;
                min = nums[i];
            }
        }
        return res;
    }
}

90%

最优解

class Solution {
    public int minMoves(int[] nums) {

        int min = Integer.MAX_VALUE;
        int sum =0;
        for(int i : nums){
            if(i<min){
                min = i;
            }
            sum += i;
        }
        sum = sum - min;
        return sum-((nums.length-1)*min);

    }
}

这种方法确实更好:遍历数组,记录最小值并求和。最后用sum减去n个最小值就是结果。

P455. Assign Cookies (Easy)

每个孩子最多给一个饼干。饼干的大小不一样。每个孩子都有一个贪婪因子gi,代表能满足他的最小尺寸(的饼干)。-.-

每个饼干都有一个尺寸sj,如果sj >= gi,就可以把这个饼干分给这个孩子i。求最多可以满足多少个孩子。

我的思路

这个题其实就是田忌赛马,求第二个数组最多有多少个数是大于等于第一个数组里的数的。如果用nlogn把两个数组都排个序,那其实是很容易解决的。但如果想降到m+n,暂时想不到。。。

我的代码

public class E_455_AssignCookies {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int counter = 0;
        for (int i = 0, j = 0; i < s.length && j < g.length; i++) {
            if (s[i] >= g[j]) {
                counter++;
                j++;
            }
        }
        return counter;
    }
}

98%

看了最优解,他自己实现了一个排序算法,不理解为啥不用Java自带的。。。另外一个答案代码也很长,提升性能也很有限,不如就用我自己这个。

tags: LeetCode