Jerry's Blog

Recording what I learned everyday

View on GitHub


12 October 2019

LeetCode(34) -- 804, 806, 811, 812, 819

by Jerry Zhang

P804. Unique Morse Code Words (Easy)

26个字母都可以用摩斯密码来表示。

我的思路

只想到暴力求解:根据密码表翻译成摩斯密码,然后放到HashSet里,计数。想找摩斯密码的规律的话,看密码解密可能会有哪些字母的组合,这个难度有点大。。。

我的代码

public class E_804_UniqueMorseCodeWords {
    public int uniqueMorseRepresentations(String[] words) {
        String[] table = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",
                ".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
        HashSet<String> set = new HashSet<>();
        for (int i = 0; i < words.length; i++) {
            String word = words[i];
            char[] chars = word.toCharArray();
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < chars.length; j++) {
                sb.append(table[chars[j] - 'a']);
            }
            set.add(sb.toString());
        }
        return set.size();
    }
}

100% 看来也就如此了,也没什么更好的办法了。

最优解

class Solution {
    public int uniqueMorseRepresentations(String[] words) {
        String[] MORSE = {".-","-...","-.-.","-..",".","..-.","--.",
                         "....","..",".---","-.-",".-..","--","-.",
                         "---",".--.","--.-",".-.","...","-","..-",
                         "...-",".--","-..-","-.--","--.."};

        Set<String> seen = new HashSet();
        for (String word: words) {
            StringBuilder code = new StringBuilder();
            for (char c: word.toCharArray())
                code.append(MORSE[c - 'a']);
            seen.add(code.toString());
        }

        return seen.size();
    }
}

基本跟我完全一样。就是loop时没用fori,用了iter而已。

P806. Number of Lines To Write String (Easy)

写一个字符串,每个字母的宽度通过一个数组给出。每行的宽度是100个单位。判断写这个字符串需要几行,最后一行多宽。

我的思路

比较简单,每个字母去查一下表,把宽度累加起来即可。需要注意的是,不能简单地把总宽度算出来。因为到行尾有可能放不下一个字母了,就要换行。所有每次累加时要验证一下是否超过了100。

我的代码

public class E_806_NumberOfLinesToWriteString {
    public int[] numberOfLines(int[] widths, String S) {
        char[] chars = S.toCharArray();
        int lines = 1;
        int currentWidth = 0;
        for (char c : chars) {
            currentWidth += widths[c - 'a'];
            if (currentWidth > 100) {
                lines++;
                currentWidth = widths[c - 'a'];
            }
        }

        int[] ans = {lines, currentWidth};
        return ans;
    }
}

100%

最优解

class Solution {
    public int[] numberOfLines(int[] widths, String S) {
        int line = 1;
        int count = 0;
        for (int i = 0; i < S.length(); i++) {
            int w = widths[S.charAt(i) - 'a'];
            if (count + w > 100) {
                count = w;
                line++;
            } else {
                count += w;
            }
        }

        return new int[]{line, count};
    }
}

差不多。简单题基本上思路都一样。

P811. Subdomain Visit Count (Easy)

给一组字符串,用来表示每个域名的访问次数。比如”9001 discuss.leetcode.com”代表这个网址被访问了9001次。 访问域名时,其所有层级的父域名也被同时访问,比如leetcode.com和com。计算所有域名的访问次数。

我的思路

hashmap计数即可。

我的代码

public class E_811_SubdomainVisitCount {
    public List<String> subdomainVisits(String[] cpdomains) {
        HashMap<String, Integer> map = new HashMap<>();
        for (String cpdomain : cpdomains) {
            String[] split = cpdomain.split(" ");
            while (split[1].contains(".")) {
                map.put(split[1], Integer.parseInt(split[0]) + map.getOrDefault(split[1], 0));
                split[1] = split[1].substring(split[1].indexOf(".") + 1);
            }
            map.put(split[1], Integer.parseInt(split[0]) + map.getOrDefault(split[1], 0));
        }
        List<String> list = new ArrayList<>();
        for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {
            list.add(stringIntegerEntry.getValue() + " " + stringIntegerEntry.getKey());
        }
        return list;
    }
}

68%

最优解

class Solution {
    public List<String> subdomainVisits(String[] cpdomains) {
        Map<String, DomainInfo> cmap = new HashMap<>();
        for (String cpdomain : cpdomains) {
            addCpDomain(cmap, cpdomain);
        }
        ArrayList<String> result = new ArrayList<>(cmap.size());
        for (Map.Entry<String, DomainInfo> e : cmap.entrySet()) {
            result.add(e.getValue().count + " " + e.getKey());
        }
        return result;
    }

    void addCpDomain(Map<String, DomainInfo> cmap, String cpdomain) {
        int spaceIndex = cpdomain.indexOf(' ');
        int count = Integer.parseInt(cpdomain.substring(0, spaceIndex));
        String domain = cpdomain.substring(spaceIndex + 1);
        addInfo(cmap.get(domain), cmap, count, domain);
    }

    DomainInfo addInfo(DomainInfo d, Map<String, DomainInfo> cmap, int count,
                       String domain) {
        if (d == null) {
            // there is nothing to do if the domain is null too
            if (domain == null) {
                return null;
            }
            final String updomain = getUpDomain(domain);
            d = new DomainInfo(count, addInfo(cmap.get(updomain), cmap, count, updomain));
            cmap.put(domain, d);
        } else {
            d.count += count;
            for (DomainInfo tmp = d.updomain; tmp != null; tmp = tmp.updomain) {
                tmp.count += count;
            }
        }
        return d;
    }

    String getUpDomain(String domain) {
        int dotIndex = domain.indexOf('.');
        if (dotIndex >= 0) {
            return domain.substring(dotIndex + 1);
        }
        return null;
    }

    static class DomainInfo {
        int count;
        DomainInfo updomain;

        DomainInfo(int count, DomainInfo updomain) {
            this.count = count;
            this.updomain = updomain;
        }
    }
}

P812. Largest Triangle Area (Easy)

在平面上有一些点,任意三个点,可以组成的三角形中,最大面积是多少。

答案

public class E_812_LargestTriangleArea {
    public double largestTriangleArea(int[][] points) {
        double ans = 0;
        int n = points.length;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                for (int k = j + 1; k < n; k++) {
                    ans = Math.max(ans, area(points[i], points[j], points[k]));
                }
            }
        }
        return ans;
    }

    private double area(int[] P, int[] Q, int[] R) {
        return 0.5 * Math.abs(P[0] * Q[1] + Q[0] * R[1] + R[0] * P[1] -
                P[1] * Q[0] - Q[1] * R[0] - R[1] * P[0]);
    }
}

鞋带算法求面积。

P819. Most Common Word (Easy)

给一段文字,还有一组禁止的词。找出所有没被禁的词中,出现频率最高的一个。

我的思路

HashSet,HashMap

我的代码

public class E_819_MostCommonWord {
    public String mostCommonWord(String paragraph, String[] banned) {
        HashSet<String> set = new HashSet<>();
        Collections.addAll(set, banned);
        int max = 0;
        String ans = null;
        String lowerCase = paragraph.toLowerCase();
        String[] strings = lowerCase.split("[^\\w]");
        HashMap<String, Integer> map = new HashMap<>();
        for (String string : strings) {
            if (!string.equals("") && !set.contains(string)) {
                int count = map.getOrDefault(string, 0) + 1;
                if (count > max) {
                    max = count;
                    ans = string;
                }
                map.put(string, count);
            }
        }
        return ans;
    }

    public static void main(String[] args) {
        String[] banned = {"hit"};
        new E_819_MostCommonWord().mostCommonWord("Bob hit a ball, the hit BALL flew far after it was hit.", banned);
    }
}

24%

最优解

class Solution {
    public String mostCommonWord(String paragraph, String[] banned) {
        //insert banned words into trie
        Trie root = new Trie();
        Trie cur = root;
        for(String b:banned){
            for(char c:b.toCharArray()){
                if(cur.next[c-'a'] == null){
                    cur.next[c-'a'] = new Trie();
                }
                cur = cur.next[c-'a'];
            }
            cur.ban = true;
            cur = root;
        }
        String maxWord = "";
        int maxFreq = 0;
        String para = paragraph.toLowerCase();
        char[] p = para.toCharArray();
        int n = p.length;
        int start = 0, end = 0;
        for(start = 0; start < n; start = end+1){
            //move past non alphabetic characters
            while(start < n && (p[start] < 'a' || p[start] > 'z')){
                start++;
            }
            for(end = start; end < n && p[end] >= 'a' && p[end] <= 'z'; end++){
                char c = p[end];
                if(cur.next[c-'a'] == null){
                    cur.next[c-'a'] = new Trie();
                }
                cur = cur.next[c-'a'];
            }
            cur.freq++;

            if(cur.freq > maxFreq && !cur.ban){
                maxFreq = cur.freq;
                maxWord = para.substring(start,end);
            }

            cur = root;
        }
        return maxWord;
    }
}

    public class Trie{
        Trie[] next = new Trie[26];
        boolean ban;
        int freq;
    }

答案:

class Solution {
    public String mostCommonWord(String paragraph, String[] banned) {
        paragraph += ".";

        Set<String> banset = new HashSet();
        for (String word: banned) banset.add(word);
        Map<String, Integer> count = new HashMap();

        String ans = "";
        int ansfreq = 0;

        StringBuilder word = new StringBuilder();
        for (char c: paragraph.toCharArray()) {
            if (Character.isLetter(c)) {
                word.append(Character.toLowerCase(c));
            } else if (word.length() > 0) {
                String finalword = word.toString();
                if (!banset.contains(finalword)) {
                    count.put(finalword, count.getOrDefault(finalword, 0) + 1);
                    if (count.get(finalword) > ansfreq) {
                        ans = finalword;
                        ansfreq = count.get(finalword);
                    }
                }
                word = new StringBuilder();
            }
        }

        return ans;
    }
}
tags: LeetCode