Jerry's Blog

Recording what I learned everyday

View on GitHub


20 September 2019

LeetCode(13) -- 476, 482, 496

by Jerry Zhang

P476. Number Complement (Easy)

给一个正整数,求它的二进制的“补”

Input: 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.

我的思路

直接给这个数用位运算 “~”取个补。但问题是给定的要求前面的0不要取反。做题的时候发现,二进制我只会从右往左一位一位读,如果想把读到的数copy到另一个变量中,就不知道怎么办了。

讨论区

class Solution {
    public int findComplement(int num) {
        int powerOf2 = 1;
        while (num > powerOf2) {
            powerOf2 <<= 1;
            powerOf2++;
        }
        return num ^ powerOf2;
    }
}

有几位就生成几个1,最后把这些1跟原数做异或运算。

最优解

class Solution {
    public int findComplement(int num) {
        long i = 2;
        while (i < num) {
            i *= 2;
        }

        if (i == (long)num) return (int) (i-1);

        return (int) (i-1-num);
    }
}

把i初始化为二进制“10”,然后不断把1向左移,直到不小于原数为止。比如原数如果是5,也就是“101”,那就把1移动成“1000”。

接下来会有两种可能,一种是等于原数,另一种是大于原数。

如果等于原数,取反其实就是-1。如果大于原数,取反就是-1再减去原数。这就类似用“9999”减去某个四位数比如“6542”,得到的结果就是它的“补”。

P482. License Key Formatting (Easy)

字母加数字的授权码,用N个“-”分隔。给一个整数K,比如4。重新格式化这个授权码,使之变成K个字母为一组。

Input: S = "5F3Z-2e-9-w", K = 4

Output: "5F3Z-2E9W"

Explanation: The string S has been split into two parts, each part has 4 characters.
Note that the two extra dashes are not needed and can be removed.

我的思路

简单的字符串拼接。

我的代码

public class E_482_LicenseKeyFormatting {
    public String licenseKeyFormatting(String S, int K) {
        String s = S.replaceAll("-", "");
        StringBuilder sb = new StringBuilder();
        int remainder = s.length() >= K ? s.length() % K : 0;
        int index = 0;
        for (int i = 0; i < remainder; i++) {
            sb.append(s.charAt(index));
            index++;
        }
        if (remainder != 0) {
            sb.append("-");
        }
        for (int i = 0; i < s.length() - remainder; i++) {
            sb.append(s.charAt(index));
            if ((i + 1) % K == 0 && (i + 1) != s.length() - remainder) {
                sb.append("-");
            }
            index++;
        }
        return sb.toString().toUpperCase();
    }

    public static void main(String[] args) {
        new E_482_LicenseKeyFormatting().licenseKeyFormatting("2-5g-3-J",2);
    }
}

51%

最优解

class Solution {
    public String licenseKeyFormatting(String S, int K) {
		if(S == null ||S.length() == 0) return S;
        int len = S.length() / K + S.length();
        if(S.length() % K == 0) len--;
        char[] array = new char[len];
        int j = len - 1;
        int counter = 0;
        for(int i = S.length() - 1; i >= 0; i--) {
            char c = S.charAt(i);
            if(c != '-') {
                if(c >= 'a') c = (char) ('A' + c - 'a');
                array[j--] = c;
                counter++;
                if(counter == K && i != 0) {
                    array[j--] = '-';
                    counter = 0;
                }
            }
        }
        if(j + 1 < len && array[j + 1] == '-') j++;
        return new String(array, j + 1, len - j - 1);
    }
}

先创建了一个字符型的数组,用来存最后的结果。那么首先第一个问题就是这个数组应该有多长。如果先把字符串中的“-”去除,那当然很容易算出这个数组有多长。但他为了性能,并没有去除“-”,而是算了一下这个数组最多可能有多长。也就是算出了长度的上限。怎么算呢?原始字符串如果不包含任何“-”,那它的长度至少也是它本身。后期我们往中间插入几个“-”呢?可以分成几组,就插入几个。根据是否能整除再做一下调整。

然后开始从右向左遍历原始字符串。只有在不是“-”时才进行操作。用j来记录结果集的index,一般情况下就直接赋值即可。当然如果是小写字母,要转化成大写字母。又用一个counter来记录是否是k的整数倍,决定是否要额外添加一个“-”。

最后如果第一个字符得到的是“-”,就把j向右移回去一位(因为刚才j一直是从左往右移动的)。最后返回数组中从j+1开始,一直到最右边所构成的字符串。

P496. Next Greater Element I (Easy)

给两个数组,第一个数组是第二个数组的子集。数组中的数都不重复。求第一个数组中的每个数,对应到第二个数组后,下一个比它大的数。

Input: nums1 = [4,1,2], nums2 = [1,3,4,2].
Output: [-1,3,-1]
Explanation:
    For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
    For number 1 in the first array, the next greater number for it in the second array is 3.
    For number 2 in the first array, there is no next greater number for it in the second array, so output -1.
Input: nums1 = [2,4], nums2 = [1,2,3,4].
Output: [3,-1]
Explanation:
    For number 2 in the first array, the next greater number for it in the second array is 3.
    For number 4 in the first array, there is no next greater number for it in the second array, so output -1.

我的思路

做出来不难,主要是怎么降低时间复杂度。我想用HashMap存下第二个数组中每个数的index,再从第一个数组中遍历就可以很快找到了,然后再往后推,找一个比它大的数即可。

我的代码

public class E_496_NextGreaterElementI {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums2.length; i++) {
            map.put(nums2[i], i);
        }
        int[] res = new int[nums1.length];
        for (int i = 0; i < nums1.length; i++) {
            int current = nums1[i];
            Integer index = map.get(current);
            while (index + 1 < nums2.length) {
                if (nums2[index + 1] > current) {
                    res[i] = nums2[index + 1];
                    break;
                }
                index++;
            }
            if (index + 1 == nums2.length) {
                res[i] = -1;
            }
        }
        return res;
    }
}

80%

最优解

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        int l1 = nums1.length, l2 = nums2.length;
        int[] res = new int[l1];
        if (l1 > l2 || l1 == 0 || l2 == 0){
            return res;
        }
        int maxNum = nums2[0];
        for(int k = 1; k < l2; k++){
            if (nums2[k] > maxNum){
                maxNum = nums2[k];
            }
        }
        int[] hashNums = new int[maxNum+1];
        int i, j;

        for(i=0; i<l2-1; i++){
            for(j=i+1; j<l2; j++){
                if(nums2[j]>nums2[i]){
                    hashNums[nums2[i]] = nums2[j];
                    break;
                }
            }
            if (j==l2){
                hashNums[nums2[i]] = -1;
            }
        }
        hashNums[nums2[l2-1]] = -1;
        for(i=0; i<l1; i++){
            res[i] = hashNums[nums1[i]];
        }
        return res;
    }
}

先找出第二个数组里的最大值,然后以这个最大值+1作为长度,新建一个数组。这是要自制HashMap。

然后第二个数组开始loop,找每一个数的下一个大于它的数,找到后存到HashMap里。最后一个不可以有更大的数,直接返回-1。

最后loop一遍nums1,每个数去HashMap里直接找到对应的值即可。

tags: LeetCode