Jerry's Blog

Recording what I learned everyday

View on GitHub


30 October 2019

LeetCode(53) -- 1103, 1108, 1122, 1128, 1137, 1154,

by Jerry Zhang

P1103. Distribute Candies to People (Easy)

有一些糖果分给n个人,第一个人分一个,第二个人分两个。。。直到第n个人分n个。如果糖果还有剩余,再从第一个人开始,分n+1个,第二个人分n+2个。。。直到分完所有糖果。

我的思路

最简单的方法就是情景模拟,按题目要求实现代码即可。

我的代码

class Solution {
    public int[] distributeCandies(int candies, int num_people) {
        int[] ans = new int[num_people];
        int count = 1;
        while (candies != 0) {
            for (int i = 0; i < num_people; i++) {
                if (candies - count >= 0) {
                    ans[i] += count;
                    candies -= count;
                    count++;
                } else {
                    ans[i] += candies;
                    candies = 0;
                    break;
                }
            }
        }
        return ans;
    }
}

92%

最优解

class Solution {
    public int[] distributeCandies(int candies, int num_people) {
        int[] res = new int[num_people];
        int turn = num_people * (num_people + 1) / 2;
        int nturn = 0;
        while (candies >= turn) {
            candies -= turn;
            turn += num_people * num_people;
            nturn++;
        }
        res[0] = nturn + (nturn - 1) * nturn / 2 * num_people;
        for (int i = 1; i < num_people; ++i) {
            res[i] = res[i - 1] + nturn;
        }
        int gift = nturn * num_people + 1;
        int i = 0;
        while (candies > 0) {
            if (candies >= gift) {
                res[i] += gift;
                candies -= gift;
                gift++;
            } else {
                res[i] += candies;
                candies = 0;
            }
            ++i;
        }
        return res;
    }
}

P1108. Defanging an IP Address (Easy)

IP地址,把所有的”.”都换成”[.]”

我的思路

不明白这题有什么意义。。。。

我的代码

class Solution {
    public String defangIPaddr(String address) {
        return address.replaceAll("\\.", "[.]");
    }
}

48%

class Solution {
    public String defangIPaddr(String address) {
        StringBuilder sb = new StringBuilder();
        for (char c : address.toCharArray()) {
            if (c == '.') {
                sb.append("[.]");
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}

100%

最优解

class Solution {
    public String defangIPaddr(String address) {
        StringBuilder add = new StringBuilder(address.length() + 32);
    String search = ".";
    String replacement = "[.]";
    int start = 0;
    int found = address.indexOf(search, start);
    while (found != -1) {
        add.append(address.substring(start, found)).append(replacement);
        start = found + search.length();
        found = address.indexOf(search, start);
    }
    add.append(address.substring(start));
    return add.toString();
    }
}

有一点值得学习,indexOf可以设置起始点。其他没什么值得学的,用toCharArray即可。

P1122. Relative Sort Array (Easy)

两个整数数组arr1和arr2,arr2没有重复且arr1包含arr2中的所有数。现在要把arr1按照arr2中数字出现的顺序排序,剩下的没有在arr2中的数字按升序排序。

我的思路

用统计法非常容易就能做出来。

我的代码

class Solution {
    public int[] relativeSortArray(int[] arr1, int[] arr2) {
        int[] count = new int[1001];
        for (int i : arr1) {
            count[i]++;
        }
        int[] ans = new int[arr1.length];
        int indexAns = 0;
        for (int i : arr2) {
            while (count[i] != 0) {
                ans[indexAns++] = i;
                count[i]--;
            }
        }
        for (int i = 0; i < count.length; i++) {
            while (count[i] != 0) {
                ans[indexAns++] = i;
                count[i]--;
            }
        }
        return ans;
    }
}

100%

最优解

class Solution {
    public int[] relativeSortArray(int[] arr1, int[] arr2) {
int[] counter = new int[1001];
        for(int i:arr1)
            counter[i]++;
        int[] result = new int[arr1.length];
        int index=0;
        for(int j:arr2){
            for(int i=0;i<counter[j];i++)
                result[index++]=j;
            counter[j]*=-1;
        }
        for(int j=0;j<1001;j++){
             for(int i=0;i<counter[j];i++)
                result[index++]=j;
            counter[j]*=-1;
        }
        return result;
    }
}

感觉我的代码更好。

P1128. Number of Equivalent Domino Pairs (Easy)

相等的多米诺骨牌对有多少

Input: dominoes = [[1,2],[2,1],[3,4],[5,6]]
Output: 1

我的思路

因为只有1到9,所以我就用两个二位数来表示一个骨牌。比如骨牌上是1和2,就用12和21来表示。

我的代码

class Solution {
    public int numEquivDominoPairs(int[][] dominoes) {
        int[] hashTable = new int[100];
        int count = 0;
        for (int[] domino : dominoes) {
            int i1 = domino[0] * 10 + domino[1];
            int i2 = domino[1] * 10 + domino[0];
            count += hashTable[i1];
            hashTable[i1]++;
            if (i1 != i2) {
                hashTable[i2]++;
            }
        }
        return count;
    }
}

98% 出的bug是如果两个数字是一样的,只需要加一次。

最优解

class Solution {
    public int numEquivDominoPairs(int[][] dominoes) {
        int output = 0;

        int[][] table = new int[10][10];

        for (int i = 0; i < dominoes.length; i++) {
            table[dominoes[i][0]][dominoes[i][1]]++;
        }

        for (int i = 1; i < 10; i++) {
            for (int j = 1; j < 10; j++) {
                int n = 0;
                if (i != j) {
                    n = Math.max(table[i][j] + table[j][i] - 1, 0);
                } else {
                    n = Math.max(table[i][j] - 1, 0);
                }

                output += n*(n + 1)/2;
                table[i][j] = 0;
                table[j][i] = 0;
            }
        }
        return output;
    }
}

用一个二维数组,把出现的次数记下来,然后求每一个数以及它颠倒后出现次数的最大值。 然后求1到n的和,就是pair的个数。

P1137. N-th Tribonacci Number (Easy)

斐波那契数列的变体,每个数都是前三个数相加的结果。

我的思路

斐波那契数列就有很多种方法,怎么做都可以,只要别搞成3^n就行了。

我的代码

class Solution {
    public int tribonacci(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        if (n == 2) return 1;
        int[] tri = new int[n+1];
        tri[0] = 0;
        tri[1] = 1;
        tri[2] = 1;
        for (int i = 3; i < n + 1; i++) {
            tri[i] = tri[i - 1] + tri[i - 2] + tri[i - 3];
        }
        return tri[n];
    }
}

100%

P1154. Day of the Year (Easy)

给一个”YYYY-MM-DD”格式的日期,返回这一天是当年的第几天。

我的思路

用某人函数应该可以返回日期的差。或者按每个月的天数数一下,注意闰年的问题。(鉴于闰年比较麻烦,还是尽量用内置的函数吧。。。)

最优解

class Solution {
    public int dayOfYear(String date) {
        int[] dpm = new int[] {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};

        int day = (date.charAt(8) - '0') * 10 + date.charAt(9) - '0';
        int month = (date.charAt(5) - '0') * 10 + date.charAt(6) - '0';
        int year = (((date.charAt(0) - '0') * 10 + date.charAt(1) - '0') * 10 + date.charAt(2) - '0') * 10 + date.charAt(3) - '0';

        int leapYear = (month > 2 && (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)) ? 1 : 0;

        return dpm[month - 1] + day + leapYear;
    }
}

P1160. Find Words That Can Be Formed by Characters (Easy)

给一些单词和一个字符串chars。一个单词是“好”的如果它能用chars里的字母构成,每个字母只能使用一次。

我的思路

把chars的所有字母统计在一个table里,然后每个单词用一个字母就消耗一次,一旦消耗完,就说明不是good

我的代码

class Solution {
    public int countCharacters(String[] words, String chars) {
        int[] table = new int[26];
        for (char c : chars.toCharArray()) {
            table[c - 'a']++;
        }
        int sum = 0;
        for (String word : words) {
            int[] clone = table.clone();
            int i;
            for (i = 0; i < word.length(); i++) {
                char c = word.charAt(i);
                if (clone[c - 'a'] == 0) {
                    break;
                }
                clone[c - 'a']--;
            }
            if (i == word.length()) {
                sum += word.length();
            }
        }
        return sum;
    }
}

80%

最优解

class Solution
{
    public int countCharacters(String[] words, String chars)
    {
        // Array that counts the frequency
        int[] char_counts = new int[26];
        for (char c : chars.toCharArray())
        {
            char_counts[c - 'a']++;
        }

        int count = 0;
        // Iterate through the words and
        for (String word : words)
        {
            // If we can form the word, then add to string
            if (is_valid(word, char_counts))
            {
                count += word.length();
            }
        }

        return count;
    }
    // Function checks if we can make the word w/ count
    boolean is_valid(String word, int[] count)
    {
        // Word Frequency
        int[] used = new int[26];
        for (char c : word.toCharArray())
        {
            used[c - 'a']++;
            // returns false if we use more than we have
            if (used[c - 'a'] > count[c - 'a']) return false;
        }

        return true;
    }
}

感觉跟我的差不多。

P1170. Compare Strings by Frequency of the Smallest Character (Easy)

一个函数f(s),返回一个字符串中,最小的字母出现的次数。最小的字母是指最靠前的,比如a < b, b < c。

给一个字符串数组words,以及另一个字符串数组queries。对于query 中的每一个单词,问在words中有多少单词的函数值大于该单词的函数值。

我的思路

先写出来这个函数,然后把words中的每个单词都求出来对应的函数值,放在一个新数组中。然后遍历queries,看每个单词的函数值,在words中有多少数比它大。

我的代码

class Solution {
    public int[] numSmallerByFrequency(String[] queries, String[] words) {
        int[] ans = new int[queries.length];
        int[] word_f = new int[words.length];
        for (int i = 0; i < words.length; i++) {
            word_f[i] = f(words[i]);
        }
        Arrays.sort(word_f);
        for (int i = 0; i < queries.length; i++) {
            int target = f(queries[i]);
            ans[i] = binarySearch(word_f, target);
        }
        return ans;
    }

    private int f(String s) {
        int count = 0;
        char smallest = 'z';
        for (char c : s.toCharArray()) {
            if (c < smallest) {
                count = 1;
                smallest = c;
            } else if (c == smallest) {
                count++;
            }
        }
        return count;
    }

    private int binarySearch(int[] word_f, int target) {
        if (word_f.length == 1) {
            if (word_f[0] > target) {
                return 1;
            } else {
                return 0;
            }
        }
        int l = 0;
        int r = word_f.length - 1;
        while (l <= r) {
            if (l == r) {
                return word_f.length - l - 1;
            }
            int mid = l + (r - l) / 2;
            if (target >= word_f[mid] && target < word_f[mid + 1]) {
                return word_f.length - mid - 1;
            }
            if (target < word_f[mid]) {
                if (mid == 0) {
                    return word_f.length;
                }
                r = mid - 1;
            } else if (target >= word_f[mid+1]) {
                l = mid + 1;
            }
        }
        return 0;
    }
}

89%,这个binary search 居然写了好几个小时才算终于没bug了。。。

最优解

class Solution {
    public int[] numSmallerByFrequency(String[] queries, String[] words) {

	   //running sum of number of words with f(W)>=index
		int[] counts = new int[12];
		for (String word : words) counts[f(word)]++;
        for (int i=10; i>=0; i--) counts[i] += counts[i+1];

        int[] ans = new int[queries.length];
		for (int i=0; i<queries.length; i++) ans[i]=counts[f(queries[i])+1];
        return ans;
    }

    private int f(String s) {
        char minChar = Character.MAX_VALUE;
        int freq = 0;
        for (int i=0; i< s.length(); i++) {
            char ch = s.charAt(i);
            if (ch<minChar) {
                freq=1;
                minChar=ch;
            }
            else if (ch==minChar) freq++;
        }
        return freq;
    }
}

函数值最多就是10,所以存成counts,然后从后往前累加,其结果就是有多少个数比这个数大。

P1175. Prime Arrangements (Easy)

我的思路

我的代码

class Solution {
    public int numPrimeArrangements(int n) {
        int prime = countPrimes(n + 1);
        long ans = 1;
        for (int i = 1; i <= prime; i++) {
            ans *= i;
            ans = ans % 1000000007;
        }
        for (int i = 1; i <= n - prime; i++) {
            ans *= i;
            ans = ans % 1000000007;
        }
        return (int)ans;
    }

    private int countPrimes(int n) {
        if (n < 3) {
            return 0;
        }
        boolean[] f = new boolean[n];
        int count = n / 2;
        for (int i = 3; i * i < n; i += 2) {
            if (f[i]) {
                continue;
            }
            for (int j = i * i; j < n; j += 2 * i) {
                if (!f[j]) {
                    count--;
                    f[j] = true;
                }
            }
        }
        return count;
    }
}

100%

最优解

class Solution {
    public int numPrimeArrangements(int n) {
        if(n <= 2) {
            return 1;
        }
        int count = countPrime(n);
        long sum = 1;
        for(int i = 2; i <= count; i++) {
            sum = (sum * i) % 1000000007;
        }
        for(int i = n - count; i >= 2; i--) {
            sum = (sum * i) % 1000000007;
        }
        return (int)(sum % 1000000007);
    }

    private int countPrime(int n) {
        int count = 0;
        boolean[] v = new boolean[n + 1];
        for(int i = 2; i * i <= n; i++) {
            for(int j = 2; j * i <= n; j++) {
                v[i * j] = true;
            }
        }
        for(int i = 2; i <= n; i++) {
            if(!v[i] && isPrime(i)) {
                count++;
            }
        }
        return count;
    }

    private boolean isPrime(int val) {
        for(int i = 2; i * i <= val; i++) {
            if(val % i == 0) {
                return false;
            }
        }
        return true;
    }
}
tags: LeetCode