前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode Weekly Contest 33解题思路

LeetCode Weekly Contest 33解题思路

作者头像
用户1147447
发布2019-05-26 09:47:10
3640
发布2019-05-26 09:47:10
举报
文章被收录于专栏:机器学习入门机器学习入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1434764

LeetCode Weekly Contest 33解题思路

详细代码可以fork下Github上leetcode项目,不定期更新。

赛题

本次周赛主要分为以下4道题:

594 Longest Harmonious Subsequence (3分)

Problem:

We define a harmonious array is an array where the difference between its maximum value and its minimum value is exactly 1. Now, given an integer array, you need to find the length of its longest harmonious subsequence among all its possible subsequences.

Example 1:

Input: 1,3,2,2,5,2,3,7 Output: 5 Explanation: The longest harmonious subsequence is 3,2,2,2,3.

Note:

  • The length of the input array will not exceed 20,000.

思路:

对数组中的每个数进行计数,遍历所有的key,累加key和key+1的个数,取最大即可,代码如下:

代码语言:javascript
复制
public int findLHS(int[] nums) {
        Map<Integer,Integer> count = new HashMap<>();
        for (int i = 0; i < nums.length; i++){
            count.put(nums[i], count.getOrDefault(nums[i], 0)+1);
        }
        int max = 0;
        for (int key : count.keySet()){
            if (count.containsKey(key+1)){
                max = Math.max(max, count.get(key) + count.get(key+1));
            }
        }
        return max;
    }

593 Valid Square (6分)

Problem:

Given the coordinates of four points in 2D space, return whether the four points could construct a square. The coordinate (x,y) of a point is represented by an integer array with two integers.

Example:

Input: p1 = 0,0, p2 = 1,1, p3 = 1,0, p4 = 0,1 Output: True

Note:

  • All the input integers are in the range -10000, 10000.
  • A valid square has four equal sides with positive length and four equal angles (90-degree angles).
  • Input points have no order.

思路:

利用正方形的基本性质,四条边相等且两条对角线相等。所以简单的方法,利用set,把六条边计算出来,最后剩下两条边就一定是正方形。代码如下:

代码语言:javascript
复制
    public boolean validSquare(int[] p1, int[] p2, int[] p3, int[] p4) {
        Set<Integer> set = new HashSet<Integer>();
        set.add(distance(p1, p2));
        set.add(distance(p1, p3));
        set.add(distance(p1, p4));
        set.add(distance(p2, p3));
        set.add(distance(p2, p4));
        set.add(distance(p3, p4));
        return set.size() == 2 && !set.contains(0);
    }

    private int distance(int[] p1, int[] p2){
        int x1 = p1[0] - p2[0];
        int x2 = p1[1] - p2[1];
        return x1 * x1 + x2 * x2;
    }

这道题有更一般的解法,已知四个点,p1,p2,p3,p4,如下图:

对于正方形的判断代码如下:

代码语言:javascript
复制
private int distance(int[] p1, int[] p2){
        int x1 = p1[0] - p2[0];
        int x2 = p1[1] - p2[1];
        return x1 * x1 + x2 * x2;
    }

    private boolean check(int[] p1, int[] p2, int[] p3, int[] p4){
        return distance(p1, p2) == distance(p2, p3) && distance(p2, p3) == distance(p3, p4) 
                && distance(p3, p4) == distance(p4, p1) && distance(p1, p3) == distance(p2, p4) && distance(p1,p2) != 0;
    }


    public boolean validSquare(int[] p1, int[] p2, int[] p3, int[] p4) {
        return check(p1, p2, p3, p4) || check(p1, p3, p2, p4) || check(p1, p2, p4, p3);
    }

check的代码很好理解,主要是validSquare中应该如何构造点的顺序,一个简单的做法,求出所有点的nextPermutation(),只要有一种置换序符合正方形的性质就返回true,但实际它有很多重复的计算。

而理解check的三个式子,我们可以把正方形的点分割成两条唯一对角线即可。假设有点{p1,p2,p3,p4},那么我们可以构造非重复的正方形可以有:

代码语言:javascript
复制
对角线:{p1,p3},{p2,p4}
对角线:{p1,p2},{p3,p4}
对角线:{p1,p4},{p2,p3}

也就三种情况,所以只要check以上三种情况即可。

592 Fraction Addition and Subtraction (7分)

Problem:

Given a string representing an expression of fraction addition and subtraction, you need to return the calculation result in string format. The final result should be irreducible fraction. If your final result is an integer, say 2, you need to change it to the format of fraction that has denominator 1. So in this case, 2 should be converted to 2/1.

Example 1:

Input:”-1/2+1/2” Output: “0/1”

Example 2:

Input:”-1/2+1/2+1/3” Output: “1/3”

Example 3:

Input:”1/3-1/2” Output: “-1/6”

Example 4:

Input:”5/3+1/3” Output: “2/1”

Note:

  • The input string only contains ‘0’ to ‘9’, ‘/’, ‘+’ and ‘-‘. So does the output.
  • Each fraction (input and output) has format ±numerator/denominator. If the first input fraction or the output is positive, then ‘+’ will be omitted.
  • The input only contains valid irreducible fractions, where the numerator and denominator of each fraction will always be in the range 1,10. If the denominator is 1, it means this fraction is actually an integer in a fraction format defined above.
  • The number of given fractions will be in the range 1,10.
  • The numerator and denominator of the final result are guaranteed to be valid and in the range of 32-bit int.

思路:

字符串的解析,以及求最大公约数,递归各种技术。解法:把所有问题都规约到最基本的两个分数加减问题,所以找寻字符串的第一个符号“+”或者符号“-”,注意优先级顺序,从字符串的右侧找,规约成求左侧的子问题。

假设得到了两个字符串的答案,把它们合并即可。代码如下:

代码语言:javascript
复制
public String fractionAddition(String expression) {
        if (noOpeartor(expression)) {
            return expression;
        }

        String ans = "";
        for (int i = expression.length()-1; i >= 0; i--) {
            if (expression.charAt(i) == '+' || expression.charAt(i) == '-') {
                String left = fractionAddition(expression.substring(0, i));
                String right = fractionAddition(expression.substring(i + 1));
                int fz1 = Integer.valueOf(left.split("/")[0]);
                int fz2 = Integer.valueOf(right.split("/")[0]);
                int fm1 = Integer.valueOf(left.split("/")[1]);
                int fm2 = Integer.valueOf(right.split("/")[1]);

                int time = fm1 * fm2;
                switch (expression.charAt(i)) {
                case '+': {
                    int fz3 = fz1 * fm2 + fz2 * fm1;
                    int fm3 = time;
                    ans = reduce(fz3, fm3);
                }
                    break;
                case '-': {
                    int fz3 = fz1 * fm2 - fz2 * fm1;
                    int fm3 = time;
                    ans = reduce(fz3, fm3);
                }
                    break;
                default:
                    break;
                }

                return ans;
            }
        }
        return ans;
    }

    private String reduce(int fz, int fm){
        if (fz == 0){
            return 0 + "/" + String.valueOf(fm);
        }

        int flag = fz > 0 ? 1 : -1;
        fz = Math.abs(fz);
        int num = fz;

        boolean canReduce = false;
        String ans = String.valueOf(fz*flag) + "/" + String.valueOf(fm);
        for (int i = 2; i <= num; i++){
            if(fz % i == 0 && fm % i == 0){
                fz /= i;
                fm /= i;
                canReduce = true;
                break;
            }
        }
        if (!canReduce) return ans;
        return reduce(fz*flag, fm);
    }


    private boolean noOpeartor(String expression) {
        for (int i = 0; i < expression.length(); i++) {
            if (expression.charAt(i) == '+' || expression.charAt(i) == '-') {
                if (i == 0) continue;
                return false;
            }
        }
        return true;
    }

上述是递归的做法,我们也可以直接进行迭代,不断合并也能得到答案。

思路:

对原来的expression的减法做一些改造,如:

代码语言:javascript
复制
1/3-1/2
改造:
1/3 +-1/2
然后split(" +")
这样就能得到每个分数,进行累加即可

代码如下:

代码语言:javascript
复制
private class Fraction {
        long a, b;

        Fraction(long a, long b) {
            if (b < 0) {
                a = -a;
                b = -b;
            }
            long g = gcd(Math.abs(a), Math.abs(b));
            a /= g;
            b /= g;
            this.a = a;
            this.b = b;
        }

        private long gcd(long a, long b) {
            return b == 0 ? a : gcd(b, a % b);
        }

        private Fraction add(Fraction that) {
            return new Fraction(a * that.b + b * that.a, b * that.b);
        }

        @Override
        public String toString() {
            return a + "/" + b;
        }
    }

    public String fractionAddition(String expression) {
        String[] exps = expression.replace("-", " +-").replace("+", " +").split(" +");
        Fraction zero = new Fraction(0, 1);
        for (int i = 0; i < exps.length; i++){
            if (exps[i].isEmpty()) continue;
            long a = 0;
            if(exps[i].charAt(0) == '+') a = Long.parseLong(exps[i].substring(1).split("/")[0]);
            else a = Long.parseLong(exps[i].split("/")[0]);
            long b = 0;
            if(exps[i].charAt(0) == '+') b = Long.parseLong(exps[i].substring(1).split("/")[1]);
            else b = Long.parseLong(exps[i].split("/")[1]);
            zero = zero.add(new Fraction(a, b));
        }
        return zero.toString();
    }

replace空格的原因在于split中的正则表达式“+”是一个特殊符号,识别它可以转意。所以,我们还可以这样,代码如下:

代码语言:javascript
复制
    public String fractionAddition(String expression) {
        String[] exps = expression.replace("-", "+-").split("\\+");
        Fraction zero = new Fraction(0, 1);
        for (int i = 0; i < exps.length; i++){
            if (exps[i].isEmpty()) continue;
            long a = Long.parseLong(exps[i].split("/")[0]);
            long b = Long.parseLong(exps[i].split("/")[1]);
            zero = zero.add(new Fraction(a, b));
        }
        return zero.toString();
    }

588 Design In-Memory File System (9分)

Problem:

Design an in-memory file system to simulate the following functions: ls: Given a path in string format. If it is a file path, return a list that only contains this file’s name. If it is a directory path, return the list of file and directory names in this directory. Your output (file and directory names together) should in lexicographic order. mkdir: Given a directory path that does not exist, you should make a new directory according to the path. If the middle directories in the path don’t exist either, you should create them as well. This function has void return type. addContentToFile: Given a file path and file content in string format. If the file doesn’t exist, you need to create that file containing given content. If the file already exists, you need to append given content to original content. This function has void return type. readContentFromFile: Given a file path, return its content in string format.

Example:

Input:undefined “FileSystem”,”ls”,”mkdir”,”addContentToFile”,”ls”,”readContentFromFile”[],“/”,“/a/b/c”,“/a/b/c/d”,”hello”,“/”,“/a/b/c/d”] Output: [null,[],null,null,“a”,”hello”] Explanation:

Note:

  • You can assume all file or directory paths are absolute paths which begin with / and do not end with / except that the path is just “/”.
  • You can assume that all operations will be passed valid parameters and users will not attempt to retrieve file content or list a directory or file that does not exist.
  • You can assume that all directory names and file names only contain lower-case letters, and same names won’t exist in the same directory.

。。。对我这种才刷了算法题半年的人来说,就这道题,我能做一天,更别说在一个半小时内完成四道题了。题目意思是让我们搭一个小的文件系统,数据结构用字符串代替。

分析:

文件系统,最关键的在于对文件的管理,我们使用文件都知道,它是一个树结构,且file可以分为文件夹和文件两种类型,所以我们可以设计如下数据结构:

代码语言:javascript
复制
    private class File{
            char type;
            Map<String, File> files; 
            StringBuilder content;

            //初始化文件 d表示文件夹,f表示文件
            public File(char type) {
                this.type = type;
                if (type == 'd'){
                    files = new HashMap<>();
                }
                if(type == 'f'){
                    content = new StringBuilder();
                }
            }
        }

对文件系统进行初始化:

代码语言:javascript
复制
//根目录
File root;
public FileSystem(){
    root = new File('d');
}

整个文件系统代码如下:

代码语言:javascript
复制
public class FileSystem {

    private class File {
        char type;
        Map<String, File> files;
        StringBuilder content;
        // 初始化文件 d表示文件夹,f表示文件
        public File(char type) {
            this.type = type;
            if (type == 'd') {
                files = new HashMap<>();
            }
            if (type == 'f') {
                content = new StringBuilder();
            }
        }
    }

    File root;

    public FileSystem() {
        root = new File('d');
    }

    public List<String> ls(String path) {
        String[] names = path.split("/");
        File cur = root;
        for (int i = 0; i < names.length; i++){
            String name = names[i];
            if(name.isEmpty()) continue;
            cur = cur.files.get(name);
        }

        List<String> dirs = new ArrayList<>();
        if (cur.type == 'f'){
            return Collections.singletonList(names[names.length-1]);
        }
        else{
            for (String files : cur.files.keySet()){
                dirs.add(files);
            }
            Collections.sort(dirs);
            return dirs;
        }
    }

    public void mkdir(String path) {
        String[] names = path.split("/");
        File cur = root;
        for (int i = 0; i < names.length; i++){
            String name = names[i];
            if (name.isEmpty()) continue;
            if (!cur.files.containsKey(name)){ //当前文件夹不存在
                cur.files.put(name, new File('d'));
            }
            cur = cur.files.get(name);
        }
    }

    public void addContentToFile(String filePath, String content) {
        String[] names = filePath.split("/");
        File cur = root;
        for (int i = 0; i < names.length; i++){
            String name = names[i];
            if (name.isEmpty()) continue;
            if (i == names.length - 1 && !cur.files.containsKey(name)){ //这些文件已经存在了
                cur.files.put(name, new File('f'));
            }
            cur = cur.files.get(name);
        }
        cur.content.append(content);
    }

    public String readContentFromFile(String filePath) {
        String[] names = filePath.split("/");
        File cur = root;
        for (int i = 0; i < names.length; i++){
            String name = names[i];
            if(name.isEmpty()) continue;
            if (i == names.length - 1 && !cur.files.containsKey(name)){ //这些文件已经存在了
                cur.files.put(name, new File('f'));
            }
            cur = cur.files.get(name);
        }
        return cur.content.toString();
    }

    public static void main(String[] args) {
        FileSystem fileSystem = new FileSystem();
        fileSystem.mkdir("/goowmfn");
        System.out.println(fileSystem.ls("/"));
        System.out.println(fileSystem.ls("/goowmfn"));
        fileSystem.mkdir("/z");
        System.out.println(fileSystem.ls("/"));
        System.out.println(fileSystem.ls("/"));
        fileSystem.addContentToFile("/goowmfn/c", "shetopcy");
        System.out.println(fileSystem.ls("/goowmfn/c"));
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年05月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • LeetCode Weekly Contest 33解题思路
    • 赛题
      • 594 Longest Harmonious Subsequence (3分)
        • 593 Valid Square (6分)
          • 592 Fraction Addition and Subtraction (7分)
            • 588 Design In-Memory File System (9分)
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档