Jerry's Blog

Recording what I learned everyday

View on GitHub


27 September 2019

LeetCode(27) -- 575, 581, 589

by Jerry Zhang

P575. Distribute Candies (Easy)

把偶数个糖果平均分给哥哥和妹妹,不同的数字代表不同各类的糖果。问妹妹最多可以得到多少种糖果?

我的思路

实际上这题就是问,在不超过半数的情况下,一共有多少个不同的数。可以用HashMap做。先找到最大的数,然后自制一个简易版HashMap.

我的代码

public class E_575_DistributeCandies {
    public int distributeCandies(int[] candies) {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < candies.length; i++) {
            if (candies[i] > max) {
                max = candies[i];
            }
            if (candies[i] < min) {
                min = candies[i];
            }
        }
        boolean[] map = new boolean[max - min + 1];
        for (int i = 0; i < candies.length; i++) {
            map[candies[i] - min] = true;
        }
        int res = 0;
        for (int i = 0; i < map.length; i++) {
            if (map[i]) res++;
        }
        return Math.min(res, candies.length / 2);
    }
}

99%

答案

public class Solution {
    public int distributeCandies(int[] candies) {
        HashSet < Integer > set = new HashSet < > ();
        for (int candy: candies) {
            set.add(candy);
        }
        return Math.min(set.size(), candies.length / 2);
    }
}

刚才想错了,不应该用Hashmap, 用HashSet.

最优解

class Solution {
    public int distributeCandies(int[] candies) {
        int len = candies.length;
        if (len == 0) return 0;
        int half = len / 2;

        // 种类有上限 [-100000, 100000]
        byte[] kinds = new byte[200001];
        int count = 0;

        for (int kind : candies) {
            count += 1 - kinds[kind + 100000];
            kinds[kind + 100000] = 1;
            if (count == half) break;
        }

        return count;
    }
}

直接通过给定的范围确定了数组的长度,不需要像我一样设定最大最小值。这行代码比较有意思: count += 1 - kinds[kind + 100000];。 因为他用了byte类型的数组,(当然其实我用boolean是一样的)如果是0,就用1减去0,就是1,也就是说,只要没出现过,count++。如果出现过就不加了。

P581. Shortest Unsorted Continuous Subarray (Easy)

给一个数组,找出最短的连续子数组,满足条件:只要把这个子数组从小到大排序, 整个数组也就从小到大排序了。

我的思路

可以先把这个数组从小到大排个序,然后比较原数组,找到第一个不一样的和最后一个不一样的。就是需要排序的子数组的范围。

我的代码

public class E_581_ShortestUnsortedContinuousSubarray {
    public int findUnsortedSubarray(int[] nums) {
        int[] sortedNums = nums.clone();
        Arrays.sort(sortedNums);
        Integer firstDiff = null;
        int lastDiff = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != sortedNums[i]) {
                if (firstDiff == null) {
                    firstDiff = i;
                }
                lastDiff = i;
            }
        }
        if (firstDiff == null) {
            return 0;
        }
        return lastDiff - firstDiff + 1;
    }
}

41%

最优解

class Solution {
    public int findUnsortedSubarray(int[] a) {
        int l = a.length-1, r  = 0, max = a[0], min = a[a.length-1];
        for(int i = 1; i < a.length; i++) {
            if(a[i] < max) r = i;
            if(a[i] > max) max = a[i];
        }
        for(int i = a.length-2; i >=0; i--) {
            if(a[i] > min) l = i;
            if(a[i] < min) min = a[i];
        }
        if(r <= l)return 0;
        return r-l+1;
    }
}

这个解法绝了!从前往后走一趟,再从后往前走一趟。第一趟保存随时保存最大值,如果有任何一个数小于当时遇到的最大值,就说明最右边界至少会在这里。也就是说,无论前面怎么波动,只有不断地刷新历史最大值,我才保持最右边界不变。从右往左也是一样的道理。

答案

public class Solution {
    public int findUnsortedSubarray(int[] nums) {
        Stack <Integer> stack = new Stack <Integer> ();
        int l = nums.length, r = 0;
        for (int i = 0; i < nums.length; i++) {
            while (!stack.isEmpty() && nums[stack.peek()] > nums[i])
                l = Math.min(l, stack.pop());
            stack.push(i);
        }
        stack.clear();
        for (int i = nums.length - 1; i >= 0; i--) {
            while (!stack.isEmpty() && nums[stack.peek()] < nums[i])
                r = Math.max(r, stack.pop());
            stack.push(i);
        }
        return r - l > 0 ? r - l + 1 : 0;
    }
}

P589. N-ary Tree Preorder Traversal (Easy)

前序遍历一棵树。

我的思路

这也太基础了。。。

我的代码

public class E_589_NaryTreePreorderTraversal {
    List<Integer> res = new ArrayList<>();
    public List<Integer> preorder(Node root) {
        if (root == null) return res;
        res.add(root.val);
        for (Node child : root.children) {
            preorder(child);
        }
        return res;
    }
}

100%

最优解

class Solution {

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

    public List<Integer> preorder(Node root) {
        if(root == null){
            return al;
        }
        preorderDFS(root);
        return al;
    }

    public void preorderDFS(Node root) {
        if(root != null) {
            al.add(root.val);
            List<Node> child = root.children;
            for(Node c: child) {
                preorderDFS(c);
            }
        }
    }
}

跟我的没什么不一样的,反而觉得没必要再写个辅助方法。

tags: LeetCode