LeetCode之Hash Table題目彙總

我的博客:http://blog.csdn.net/yano_nankai
LeetCode題解:https://github.com/LjyYano/LeetCode

Group Anagrams

Given an array of strings, group anagrams together.

For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"],
Return:

[
  ["ate", "eat","tea"],
  ["nat","tan"],
  ["bat"]
]

Note:

  1. For the return value, each inner list’s elements must follow the lexicographic order.
  2. All inputs will be in lower-case.

  1. 把每個string,按照字母分組,如”abc”和”cba”是一組
  2. 維護一個map,key是abc,value是abc一組string出現的下標
  3. 把每一組string找出,排序,加入結果
    public List<List<String>> groupAnagrams(String[] strs) {

        if (strs == null || strs.length == 0) {
            return new ArrayList<List<String>>();
        }

        List<List<String>> rt = new ArrayList<List<String>>();

        Map<String, ArrayList<Integer>> map = new HashMap<String, ArrayList<Integer>>();

        // 把單詞分組
        for (int i = 0; i < strs.length; i++) {
            char[] c = strs[i].toCharArray();
            Arrays.sort(c);
            String k = Arrays.toString(c);
            ArrayList<Integer> list = new ArrayList<Integer>();
            if (map.containsKey(k)) {
                list = map.get(k);
            }
            list.add(i);
            map.put(k, list);
        }

        for (String s : map.keySet()) {

            List<Integer> l = map.get(s);
            List<String> group = new ArrayList<String>();

            // 把相同字母的單詞放入同一個list
            for (Integer i : l) {
                group.add(strs[i]);
            }

            // 按字典序排序
            group.sort(new Comparator<String>() {
                public int compare(String x, String y) {
                    return x.compareTo(y);
                }
            });

            rt.add(group);
        }

        return rt;
    }

Bulls and Cows

You are playing the following Bulls and Cows game with your friend: You write down a number and ask your friend to guess what the number is. Each time your friend makes a guess, you provide a hint that indicates how many digits in said guess match your secret number exactly in both digit and position (called “bulls”) and how many digits match the secret number but locate in the wrong position (called “cows”). Your friend will use successive guesses and hints to eventually derive the secret number.

For example:

Secret number: “1807”
Friend’s guess: “7810”

Hint: 1 bull and 3 cows. (The bull is 8, the cows are 0, 1 and 7.)

Write a function to return a hint according to the secret number and friend’s guess, use A to indicate the bulls and B to indicate the cows. In the above example, your function should return "1A3B".

Please note that both secret number and friend’s guess may contain duplicate digits, for example:

Secret number:  "1123"
Friend's guess: "0111"

In this case, the 1st 1 in friend’s guess is a bull, the 2nd or 3rd 1 is a cow, and your function should return "1A1B".

You may assume that the secret number and your friend’s guess only contain digits, and their lengths are always equal.

Credits:
Special thanks to @jeantimex for adding this problem and creating all test cases.


    public String getHint(String secret, String guess) {

        if (secret == null || guess == null
                || secret.length() != guess.length()) {
            return "";
        }

        char[] s = secret.toCharArray();
        char[] g = guess.toCharArray();

        int A = 0, B = 0, n = s.length;

        // 統計bulls
        for (int i = 0; i < n; i++) {
            if (s[i] == g[i]) {
                s[i] = '#';
                g[i] = '#';
                A++;
            }
        }

        // 統計cows

        Map<Character, Integer> map = new HashMap<Character, Integer>();

        for (int i = 0; i < n; i++) {
            if (s[i] != '#') {
                if (!map.containsKey(s[i])) {
                    map.put(s[i], 1);
                } else {
                    int times = map.get(s[i]);
                    times++;
                    map.put(s[i], times);
                }
            }
        }

        for (int i = 0; i < n; i++) {
            if (g[i] != '#') {
                if (map.containsKey(g[i]) && map.get(g[i]) != 0) {
                    int times = map.get(g[i]);
                    times--;
                    map.put(g[i], times);
                    B++;
                }
            }
        }

        return A + "A" + B + "B";
    }

Count Primes

Description:

Count the number of prime numbers less than a non-negative number, n.

Credits:
Special thanks to @mithmatt for adding this problem and creating all test cases.

Hint:

  1. Let’s start with a isPrime function. To determine if a number is prime, we need to check if it is not divisible by any number less than n. The runtime complexity of isPrime_function would be O(_n) and hence counting the total prime numbers up to n would be O(n2). Could we do better?

  2. As we know the number must not be divisible by any number > n / 2, we can immediately cut the total iterations half by dividing only up to n / 2. Could we still do better?

  3. Let’s write down all of 12’s factors:

    2 × 6 = 12
    3 × 4 = 12
    4 × 3 = 12
    6 × 2 = 12
    

    As you can see, calculations of 4 × 3 and 6 × 2 are not necessary. Therefore, we only need to consider factors up to √n because, if n is divisible by some number p, then n = p × q and since pq, we could derive that p ≤ √n.

    Our total runtime has now improved to O(n1.5), which is slightly better. Is there a faster approach?

    public int countPrimes(int n) {
       int count = 0;
       for (int i = 1; i 
    public int countPrimes(int n) {

        boolean[] b = new boolean[n];

        // 將非質數標記爲true
        for (int i = 2; i * i < n; i++) {
            if (b[i] == false) {
                for (int j = i; i * j < n; j++) {
                    b[i * j] = true;
                }
            }
        }

        // count
        int c = 0;
        for (int i = 2; i < n; i++) {
            if (b[i] == false) {
                c++;
            }
        }

        return c;
    }

Fraction to Recurring Decimal

Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.

If the fractional part is repeating, enclose the repeating part in parentheses.

For example,

  • Given numerator = 1, denominator = 2, return “0.5”.
  • Given numerator = 2, denominator = 1, return “2”.
  • Given numerator = 2, denominator = 3, return “0.(6)”.

Credits:
Special thanks to @Shangrila for adding this problem and creating all test cases.


    public String fractionToDecimal(int numerator, int denominator) {

        String sign = "";

        if (Math.signum(numerator) * Math.signum(denominator) < 0) {
            sign = "-";
        }

        long n = Math.abs(numerator);
        long d = Math.abs(denominator);

        String intPart = Math.abs(n / d) + "";

        // 如果整除,直接返回結果
        if (n % d == 0) {
            return sign + intPart;
        }

        // 計算小數部分
        n %= d;
        n *= 10;

        StringBuilder sb = new StringBuilder();
        Map<Long, Integer> mod = new HashMap<Long, Integer>();

        for (int i = 0; n != 0; i++) {

            long q = n / d;

            Integer start = mod.get(n / 10);

            if (start != null) {
                sb.insert(start, "(");
                sb.append(")");
                break;
            }

            sb.append(Math.abs(q));
            mod.put(n / 10, i);

            n %= d;
            n *= 10;
        }

        String fractionalPart = sb.toString();

        return sign + intPart + "." + fractionalPart;
    }

H-Index

Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher’s h-index.

According to the definition of h-index on Wikipedia: “A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each.”

For example, given citations = [3, 0, 6, 1, 5], which means the researcher has 5 papers in total and each of them had received 3, 0, 6, 1, 5 citations respectively. Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, his h-index is 3.

Note: If there are several possible values for h, the maximum one is taken as the h-index.

Hint:

  1. An easy approach is to sort the array first.
  2. What are the possible values of h-index?
  3. A faster approach is to use extra space.

Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.


題目描述不清,實際上,H-Index的核心計算方法是:

1、將某作者的所有文章的引用頻次按照從大到小的位置排列

2、從前到後,找到最後一個滿足條件的位置,其條件爲:此位置是數組的第x個,其值爲y,必須滿足 y >= x;

    public int hIndex(int[] citations) {

        if (citations == null) {
            return 0;
        }

        int h = 0, n = citations.length;
        Arrays.sort(citations);

        for (int i = n - 1; i >= 0; i--) {
            if (citations[i] >= n - i) {
                h = n - i;
            } else {
                break;
            }
        }

        return h;
    }

H-Index II

Follow up for H-Index: What if the citations array is sorted in ascending order? Could you optimize your algorithm?

Hint:

  1. Expected runtime complexity is in O(log n) and the input is sorted.

二分查找

    public int hIndex(int[] citations) {

        int n = citations.length;
        int low = 0, high = n - 1;

        while (low <= high) {

            int mid = low + (high - low) / 2;

            if (citations[mid] == n - mid) {
                return n - mid;
            } else if (citations[mid] < n - mid) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }

        }

        return n - low;
    }

Happy Number

Write an algorithm to determine if a number is “happy”.

A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.

**Example: **19 is a happy number

  • 12 + 92 = 82
  • 82 + 22 = 68
  • 62 + 82 = 100
  • 12 + 02 + 02 = 1

Credits:
Special thanks to @mithmatt and @ts for adding this problem and creating all test cases.


1. 使用set

對每一個計算的結果進行計算,如果是1則是Happy Number;不是1且在set中出現過,則不是返回false;否則將結果加入set。

2. 利用性質,特殊數字“4”

在某一時刻,出現了4的Number肯定不Happy。

1000以內的Happy Number是:

1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100, 103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262, 263, 280, 291, 293, 301, 302, 310, 313, 319, 320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 379, 383, 386, 391, 392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496, 536, 556, 563, 565, 566, 608, 617, 622, 623, 632, 635, 637, 638, 644, 649, 653, 655, 656, 665, 671, 673, 680, 683, 694, 700, 709, 716, 736, 739, 748, 761, 763, 784, 790, 793, 802, 806, 818, 820, 833, 836, 847, 860, 863, 874, 881, 888, 899, 901, 904, 907, 910, 912, 913, 921, 923, 931, 932, 937, 940, 946, 964, 970, 973, 989, 998, 1000

13和31,101和11是一樣的,只是對每個數字的排列組合,那麼不同序列的數字是:

1, 7, 13, 19, 23, 28, 44, 49, 68, 79, 129, 133, 139, 167, 188, 226, 236, 239, 338, 356, 367, 368, 379, 446, 469, 478, 556, 566, 888, 899

500以內的Happy Primes(質數)

7, 13, 19, 23, 31, 79, 97, 103, 109, 139, 167, 193, 239, 263, 293, 313, 331, 367, 379, 383, 397, 409, 487
    public boolean isHappy(int n) {

        if (n < 1) {
            return false;
        }

        if (n == 1) {
            return true;
        }

        Set<Integer> set = new HashSet<Integer>();
        set.add(n);

        while (true) {
            int s = 0;
            while (n > 0) {
                s += (n % 10) * (n % 10);
                n /= 10;
            }
            System.out.println(s);
            if (s == 1) {
                return true;
            } else if (set.contains(s)) {
                return false;
            }
            set.add(s);
            n = s;
        }
    }
    public boolean isHappy2(int n) {

        if (n < 1) {
            return false;
        }

        if (n == 1) {
            return true;
        } else if (n == 4) {
            return false;
        }

        int s = 0;
        while (n > 0) {
            s += (n % 10) * (n % 10);
            n /= 10;
        }

        return isHappy2(s);
    }

Isomorphic Strings

Given two strings s and t, determine if they are isomorphic.

Two strings are isomorphic if the characters in s can be replaced to get t.

All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.

For example,
Given "egg", "add", return true.

Given "foo", "bar", return false.

Given "paper", "title", return true.

Note:
You may assume both s and t have the same length.


保證一對一的映射關係,即字母e映射了a,則不能再表示自身

    public boolean isIsomorphic(String s, String t) {

        if (s == null || t == null) {
            return false;
        }

        if (s.length() != t.length()) {
            return false;
        }

        Map<Character, Character> map = new HashMap<Character, Character>();
        Set<Character> set = new HashSet<Character>();

        for (int i = 0; i < s.length(); i++) {
            char c1 = s.charAt(i);
            char c2 = t.charAt(i);

            // 保證一對一的映射關係
            if (map.containsKey(c1)) {
                if (map.get(c1) != c2) {
                    return false;
                }
            } else {
                if (set.contains(c2)) {
                    return false;
                }
                map.put(c1, c2);
                set.add(c2);
            }
        }

        return true;
    }

Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for “abcabcbb” is “abc”, which the length is 3. For “bbbbb” the longest substring is “b”, with the length of 1.


    public int lengthOfLongestSubstring(String s) {

        if (s == null) {
            return 0;
        }

        if (s.length() == 0 || s.length() == 1) {
            return s.length();
        }

        char[] c = s.toCharArray();

        int barrier = 0;
        int maxLen = 1;

        for (int i = 1; i < c.length; i++) {
            for (int j = i - 1; j >= barrier; j--) {
                if (c[i] == c[j]) {
                    barrier = j + 1;
                    break;
                }
            }
            maxLen = Math.max(maxLen, i - barrier + 1);
        }

        return maxLen;
    }

Repeated DNA Sequences

All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: “ACGAATTCCG”. When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.

Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.

For example,

Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT",

Return:
["AAAAACCCCC", "CCCCCAAAAA"].

考察位圖。按位操作,A C G T分別用如下bits表示:

A   00
C   01
G   10
T   11

所以10個連續的字符,只需要20位即可表示,而一個int(32位)就可以表示。定義變量hash,後20位表示字符串序列,其餘位數置0 。

定義一個set用來存放已經出現過的hash,計算新hash時,如果已經出現過,就放入結果的set中。

    public List<String> findRepeatedDnaSequences(String s) {

        if (s == null || s.length() < 11) {
            return new ArrayList<String>();
        }

        int hash = 0;

        Set<Integer> appear = new HashSet<Integer>();
        Set<String> set = new HashSet<String>();

        Map<Character, Integer> map = new HashMap<Character, Integer>();
        map.put('A', 0);
        map.put('C', 1);
        map.put('G', 2);
        map.put('T', 3);

        for (int i = 0; i < s.length(); i++) {

            char c = s.charAt(i);

            hash = (hash << 2) + map.get(c);
            hash &= (1 << 20) - 1;

            if (i >= 9) {
                if (appear.contains(hash)) {
                    set.add(s.substring(i - 9, i + 1));
                } else {
                    appear.add(hash);
                }
            }
        }

        return new ArrayList<String>(set);
    }

Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?


對於出現2次的數字,用異或。因爲“相異爲1”,所以一個數字異或本身爲0,而0異或0仍爲0, 一個數字異或0仍爲這個數字。

0 ^ 0 = 0 
n ^ 0 = n 
n ^ n = 0
    public int singleNumber(int[] nums) {

        int n = 0;

        for (int i : nums) {
            n ^= i;
        }

        return n;
    }

Single Number II

Given an array of integers, every element appears three times except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?


對於數組{1,1,1,2}來說,分析每一位:

0 0 0 1
0 0 0 1
0 0 0 1
0 0 1 0
……………
0 0 1 3 (位數)

可以分析,分別計算每一位1的出現次數n,如果n%3==1,那麼結果中這一位就應該是1。

    public int singleNumber(int[] nums) {

        int rt = 0, bit = 1;

        for (int i = 0; i < 32; i++) {
            int count = 0;

            for (int v : nums) {
                if ((v & bit) != 0) {
                    count++;
                }
            }
            bit <<= 1;
            rt |= (count % 3) << i;
        }

        return rt;
    }

Valid Anagram

Given two strings s and t, write a function to determine if t is an anagram of s.

For example,
s = “anagram”, t = “nagaram”, return true.
s = “rat”, t = “car”, return false.

Note:
You may assume the string contains only lowercase alphabets.

Follow up:
What if the inputs contain unicode characters? How would you adapt your solution to such case?


用數組模擬哈希表,統計字符出現次數。

    public boolean isAnagram(String s, String t) {

        if (s == null || t == null) {
            return false;
        }

        if (s.length() != t.length()) {
            return false;
        }

        if (s.equals(t)) {
            return false;
        }

        int len = s.length();
        int[] map = new int[26];

        // 統計s中每個字符出現的次數
        for (int i = 0; i < len; i++) {
            map[s.charAt(i) - 'a']++;
        }

        // 減去t中相應字符出現次數
        for (int i = 0; i < len; i++) {
            map[t.charAt(i) - 'a']--;
            if (map[t.charAt(i) - 'a'] < 0) {
                return false;
            }
        }

        for (int i = 0; i < 26; i++) {
            if (map[i] != 0) {
                return false;
            }
        }

        return true;
    }

Valid Sudoku

Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.

The Sudoku board could be partially filled, where empty cells are filled with the character '.'.

A partially filled sudoku which is valid.

Note:
A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.


分別檢查行、列、3*3方塊。

    public boolean isValidSudoku(char[][] board) {

        if (board == null || board.length != 9 || board[0].length != 9) {
            return false;
        }

        int mx = board.length;
        int my = board[0].length;

        // row
        for (int x = 0; x < mx; x++) {
            boolean[] flag = new boolean[10];
            for (int y = 0; y < my; y++) {

                char c = board[x][y];
                if (c != '.') {
                    if (flag[c - '0'] == false) {
                        flag[c - '0'] = true;
                    } else {
                        return false;
                    }
                }
            }
        }

        // column
        for (int y = 0; y < my; y++) {
            boolean[] flag = new boolean[10];
            for (int x = 0; x < mx; x++) {

                char c = board[x][y];
                if (c != '.') {
                    if (flag[c - '0'] == false) {
                        flag[c - '0'] = true;
                    } else {
                        return false;
                    }
                }
            }
        }

        // square
        for (int x = 0; x < mx / 3; x++) {
            for (int y = 0; y < my / 3; y++) {

                boolean[] flag = new boolean[10];

                for (int i = 0; i < 3; i++) {
                    for (int j = 0; j < 3; j++) {

                        char c = board[x * 3 + i][y * 3 + j];
                        if (c != '.') {
                            if (flag[c - '0'] == false) {
                                flag[c - '0'] = true;
                            } else {
                                return false;
                            }
                        }
                    }
                }
            }
        }

        return true;
    }

Word Pattern

Given a pattern and a string str, find if str follows the same pattern.

Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.

Examples:

  1. pattern = "abba", str = "dog cat cat dog" should return true.
  2. pattern = "abba", str = "dog cat cat fish" should return false.
  3. pattern = "aaaa", str = "dog cat cat dog" should return false.
  4. pattern = "abba", str = "dog dog dog dog" should return false.

Notes:
You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space.

Credits:
Special thanks to @minglotus6 for adding this problem and creating all test cases.


保證1對1的映射

    public boolean wordPattern(String pattern, String str) {

        if (pattern == null || str == null) {
            return false;
        }

        String[] strs = str.split(" ");

        if (pattern.length() != strs.length) {
            return false;
        }

        Map<Character, String> map = new HashMap<Character, String>();

        for (int i = 0; i < pattern.length(); i++) {

            char c = pattern.charAt(i);

            if (map.containsKey(c)) {
                if (!map.get(c).equals(strs[i])) {
                    return false;
                }
            } else {
                // 保證1對1的映射
                if (map.containsValue(strs[i])) {
                    return false;
                }
                map.put(c, strs[i]);
            }
        }

        return true;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章