Jerry's Blog

Recording what I learned everyday

View on GitHub


11 September 2019

LeetCode(5) -- 290, 292, 299, 303, 326

by Jerry Zhang

P290. Word Pattern (Easy)

给一个字符串作为pattern,再给一个字符串作为句子,检验这个句子的每个单词是否符合这个pattern.

Input: pattern = "abba", str = "dog cat cat dog"
Output: true

我的思路

先把字符串切分成单词,然后用HashMap使之与前面的pattern相对应。

我的代码

public class E_290_WordPattern {
    public boolean wordPattern(String pattern, String str) {
        String[] words = str.split(" ");
        if (pattern.length() != words.length) {
            return false;
        }
        char[] chars = pattern.toCharArray();
        HashMap<Character, String> hashMap = new HashMap<>();
        for (int i = 0; i < chars.length; i++) {
            if (!hashMap.containsKey(chars[i]) && !hashMap.containsValue(words[i])) {
                hashMap.put(chars[i], words[i]);
            } else if (hashMap.containsKey(chars[i])) {
                if (!hashMap.get(chars[i]).equals(words[i])) {
                    return false;
                }
            } else if (hashMap.containsValue(words[i])){
                return false;
            }
        }
        return true;
    }
}

超过99.6%

最优解

class Solution {
    public boolean wordPattern(String pattern, String str) {
        HashMap<Character, String> hm = new HashMap();
        int strIndex = 0;
        for (int i = 0; i < pattern.length(); i++) {
            if (strIndex > str.length()) {
                return false;
            }
            int strEndIndex = strIndex + 1;
            while (strEndIndex < str.length() && str.charAt(strEndIndex) != ' ') {
                strEndIndex++;
            }
            String word = str.substring(strIndex, strEndIndex);
            strIndex = strEndIndex + 1;
            Character c = new Character(pattern.charAt(i));
            String s = hm.get(c);
            if (s == null) {
                if (hm.containsValue(word)) {
                    return false;
                }
                hm.put(c, word);
            } else if (!s.equals(word)) {
                return false;
            }
        }
        return (strIndex == str.length() + 1);
    }
}

P292. Nim Game (Easy)

桌上有一堆小石头,n个。两个人,每人每次可以拿走1-3个石头。拿走最后一个石头的是胜利者。

我的思路

似乎是动态规划。 每个人的策略都取决于桌上还有多少石头。如果桌上还有4个石头,我是必输的。如果桌上还有5,6,7个石头,对手必输,因为我只要给他剩下4个就行了。如果桌上有8个石头,那对手必赢,因为无论我怎么拿,对手都会剩下5,6,7个石头。如果桌上有9,10,11个石头,那我就赢了,因为我只需要给对手剩下8个石头,我一定能赢。

由此找到规律,当桌上有4个,8个,12个。。。石头的时候,我是必输的。所以只要不是4的倍数,我必赢。

我的代码

class Solution {
    public boolean canWinNim(int n) {
        return n % 4 != 0;
    }
}

超过100%

最优解

class Solution {
    public boolean canWinNim(int n) {
        return (n % 4) != 0;
    }
}

比较简单,答案很明显。

P299. Bulls and Cows (Easy)

你和你的朋友玩一个游戏:你在纸上写下一个数,比如1807,你告诉他长度是4,然后让你的朋友猜这个数。如果某个数字大小和位置都猜对了,就叫“bulls”, 记作A;如果只猜对了大小,而猜错了位置,就叫“cows”,记作B; 长度是相等的。

Example:

Input: secret = "1807", guess = "7810"

Output: "1A3B"

Explanation: 1 bull and 3 cows. The bull is 8, the cows are 0, 1 and 7.

我的思路

因为只有0到9这十个数字,就用ASCII码做一个长度为10的int数组,记录下每个数字出现的次数即可。

我的代码

public class E_299_BullsAndCows {
    public String getHint(String secret, String guess) {
        int[] digits = new int[10];
        char[] secretDigits = secret.toCharArray();
        char[] guessDigits = guess.toCharArray();
        int bulls = 0, cows = 0;
        for (int i = 0; i < secretDigits.length; i++) {
            if (secretDigits[i] == guessDigits[i]) {
                bulls++;
            } else {
                digits[secretDigits[i] - '0']++;
            }
        }
        for (int i = 0; i < guessDigits.length; i++) {
            if (secretDigits[i] != guessDigits[i] && digits[guessDigits[i] - '0'] > 0) {
                cows++;
                digits[guessDigits[i] - '0']--;
            }
        }
        return bulls + "A" + cows + "B";
    }
}

超过100%

最优解

class Solution {
    public String getHint(String secret, String guess) {
        int cow =0;
        int bull =0;
        int[] arr1 = new int[10];
        int[] arr2 = new int[10];
        for(int i=0;i< secret.length(); i++){
            char c1 = secret.charAt(i);
            char c2 = guess.charAt(i);
            if(c1==c2){
                bull++;
            }
            else{
                arr1[c1-'0']++;
                arr2[c2-'0']++;
            }
        }

        for(int i=0;i<10;i++){
            cow+= Math.min(arr1[i], arr2[i]);
        }

        return bull+"A"+cow+"B";
    }
}

跟我思路差不多,不过他用了两个数组分别记录了两个字符串每个字符出现的次数。然后两个数组的每个数,较小的那个就是cow,因为较小的数其实就是这两个字符串中,这个字符匹配上的个数,也就是猜中的次数。

这个方法比我的好,我那样先加再减,减的时候就需要重复验证这两个字符不一样,即,不是“Bulls”,比较麻烦,容易出bug。

P303. Range Sum Query - Immutable (Easy)

给一个整数数组, 求从索引i到j的所有数的和

我的思路

直接加就完了。。。

我的代码

public class E_303_RangeSumQuery {

    private int[] nums;

    public E_303_RangeSumQuery(int[] nums) {
        this.nums = nums;
    }

    public int sumRange(int i, int j) {
        int sum = 0;
        for (int k = i; k <= j; k++) {
            sum += nums[k];
        }
        return sum;
    }

}

超过7%,相比别人非常慢。

最优解

class NumArray {
    int[] sums;
    int[] nums;
    public NumArray(int[] nums) {
        this.nums = nums;
        this.sums = new int[nums.length];
        int sum = 0;
        for(int i = 0; i < nums.length; i++){
            sum += nums[i];
            this.sums[i] = sum;
        }
    }

    public int sumRange(int i, int j) {
        return this.sums[j] - this.sums[i] + this.nums[i];
    }
}

这个有点无语。。。在构造方法里先把每个数以前的和都算出来,调用的时候直接用j-i。

答案

private int[] sum;

public NumArray(int[] nums) {
    sum = new int[nums.length + 1];
    for (int i = 0; i < nums.length; i++) {
        sum[i + 1] = sum[i] + nums[i];
    }
}

public int sumRange(int i, int j) {
    return sum[j + 1] - sum[i];
}

P326. Power of Three (Easy)

给一个整数,判断它是否是3的幂。

我的思路

根据算2的幂的经验,肯定不能直接除以3。用位运算的话,3是11,9是1001,27是11011,81是1010001。。。 乘3可以看成是往左移一位,再加上自己。写到2187还是找不出来规律。。。

网上搜了一下:

我们首先分析3的幂的特点,假设一个数Num是3的幂,那么所有Num的约数都是3的幂,如果一个数n小于Num且是3的幂,那么这个数n一定是Num的约数。

了解上述性质,我们只需要找到一个最大的3的幂,看看参数n是不是此最大的幂的约数就行了,假设参数是整型,那么3的最大的幂的求法为:

int maxPower = (int) Math.pow(3,(int)(Math.log(0x7fffffff)/Math.log(3)));

0x7fffffff是整型最大值,也就是Integer.maxValue()。表达式后面两个对数相处结果为double,要转化为整型。 下一步只要判断n是不是maxPower的约数即可:

maxPower % n == 0
``` 

————————————————
版权声明本文为CSDN博主小白的学习笔记的原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接及本声明
原文链接[https://blog.csdn.net/x_i_y_u_e/article/details/50507281](https://blog.csdn.net/x_i_y_u_e/article/details/50507281)

### 最优解

```java
public class E_326_RowerOfThree {
    public boolean isPowerOfThree(int n) {
        if(n == 0) return false;
        while(n % 3 == 0) {
            n /= 3;
        }
        return n == 1;
    }
}

最快的答案反而是常规解法。。。估计测试时间出了问题。

答案:

方法一:

public class Solution {
    public boolean isPowerOfThree(int n) {
        if (n < 1) {
            return false;
        }

        while (n % 3 == 0) {
            n /= 3;
        }

        return n == 1;
    }
}

O(log(n))

方法二:

public class Solution {
    public boolean isPowerOfThree(int n) {
        return Integer.toString(n, 3).matches("^10*$");
    }
}

转化为3进制,然后看是否是“10000…”这种形式

O(log(n))

方法三:

public class Solution {
    public boolean isPowerOfThree(int n) {
        return (Math.log(n) / Math.log(3) + epsilon) % 1 <= 2 * epsilon;
    }
}

方法四:

Java中最大的整数是2147483647(MaxInt)

log_3(MaxInt) = 19.56

floor(19.56) = 19

3^19 = 1162261467

所以最大的3的幂就是1162261467,它如果能整除n,则说明n也是3的幂。

public class Solution {
    public boolean isPowerOfThree(int n) {
        return n > 0 && 1162261467 % n == 0;
    }
}

O(1) 如果执行很多次,方法四肯定是最好的。

tags: LeetCode