java学习之路

刷leetCode算法题+解析(三十)

2019-12-23  本文已影响0人  唯有努力不欺人丶

学生出勤记录1

题目:给定一个字符串来代表一个学生的出勤记录,这个记录仅包含以下三个字符:
'A' : Absent,缺勤
'L' : Late,迟到
'P' : Present,到场
如果一个学生的出勤记录中不超过一个'A'(缺勤)并且不超过两个连续的'L'(迟到),那么这个学生会被奖赏。你需要根据这个学生的出勤记录判断他是否会被奖赏。

示例 1:
输入: "PPALLP"
输出: True
示例 2:
输入: "PPALLL"
输出: False

思路:别的不说,题也不难,但是制度有点问题啊,只要不连续迟到,隔一天一迟到都奖赏,啧啧,继续说题目,其实这个应该是入门级,实现很容易,我目前打算用性能不咋地但是写起来贼方法的字符串处理方法。顺便附上一个测试案例吐个槽

这样的也是被奖赏的
算了,还是换个方法吧,说一下刚刚说的字符串处理的思路:整个字符串替换"A"为空,如果新串比原串短一个以上则false。
替换“LLL”为空,如果新串比原串短则false。
image.png

但是一想不断替换性能就好不了,所以放弃这种没技术含量的了,直接字符比对吧。

class Solution {
    public boolean checkRecord(String s) {
        int a = 0;
        int l = 0;
        char[] arr = s.toCharArray();
        for(char i:arr){
            if(i=='A'){
                a++;
                if(a>1) return false;
            }
            if(i=='L'){
                l++;
                if(l>2) return false;
            }else{
                l = 0;
            }
        }
        return true;
    }
}

这道题比较简单,不多说了,直接下一题。

反转字符串中的单词

题目:给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例 1:
输入: "Let's take LeetCode contest"

输出: "s'teL ekat edoCteeL tsetnoc"
注意:在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。

思路:这个题,我听别人说面试的时候真的考过!!!额,关于字符串处理这一块,我是觉得不考虑性能超时啥的,怎么都能做出来。我现在的思路就是根据空格分隔,每个单词反转拼接。
还没写完,但是我已经预计到我这个方法的性能之低了。其实也不是没有别的方法,还有一种用数组处理也行,感觉性能也能高一点(参考上一篇的反转字符串。不过写起来没有这个简单其实。算了,还是追求追求性能吧。毕竟遇到送分题表现好点)

class Solution {
    public String reverseWords(String s) {
        int l = 0;
        char[] arr = s.toCharArray();
        for(int i=0;i<arr.length;i++){
            if(arr[i]==' '){
                reverse(arr,l,i-1);
                l = i+1;
            }
        }
        //最后一个单词是没空格的,所以要额外处理
        reverse(arr,l,arr.length-1);
        return new String(arr);

    }
    public void reverse(char[] arr,int l,int r){
        while(l<r){
            char temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
            l++;
            r--;
        }
    }
}

一次完美通过。性能超过百分之九十七多的人。只能说我现在题感贼准,或者说对于性能有了点模糊的认识。比如我知道用字符串来回来去处理追加肯定不如这样,哈哈。既然这个性能已经不错了,我就不看题解了,直接下一题。

四叉树交集

题目:四叉树是一种树数据,其中每个结点恰好有四个子结点:topLeft、topRight、bottomLeft 和 bottomRight。四叉树通常被用来划分一个二维空间,递归地将其细分为四个象限或区域。我们希望在四叉树中存储 True/False 信息。四叉树用来表示 N * N 的布尔网格。对于每个结点, 它将被等分成四个孩子结点直到这个区域内的值都是相同的。每个节点都有另外两个布尔属性:isLeaf 和 val。当这个节点是一个叶子结点时 isLeaf 为真。val 变量储存叶子结点所代表的区域的值。
树A[图片上传中...(image.png-cde0dc-1577085907277-0)]
树B
树C

思路:说实话,题目是真的复杂。看了好几遍也没太看明白,直接看了解析,说下题目要求(自己再打一遍加深印象吧)

A || B 的意思是指

这个除了A,B都不是叶子节点,别的都比较好处理。做完回来了!这个题有bug!自己测试结果前面一个id啥的,我的没有,看了半天没看出是啥玩意,反正和答案不一样,最后一狠心已提交,居然过了。。啧啧


image.png

反正这道题感谢刚刚看的那个大佬的总结,知道那几点规则就好做多了:

/*
// Definition for a QuadTree node.
class Node {
    public boolean val;
    public boolean isLeaf;
    public Node topLeft;
    public Node topRight;
    public Node bottomLeft;
    public Node bottomRight;

    public Node() {}

    public Node(boolean _val,boolean _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) {
        val = _val;
        isLeaf = _isLeaf;
        topLeft = _topLeft;
        topRight = _topRight;
        bottomLeft = _bottomLeft;
        bottomRight = _bottomRight;
    }
};
*/
class Solution {
    public Node intersect(Node quadTree1, Node quadTree2) {
        //如果1是叶子节点并且值是false,返回2  如果2是叶子节点值是true直接返回2
        if((quadTree1.isLeaf && !quadTree1.val) || (quadTree2.isLeaf && quadTree2.val)){
            return quadTree2;
        }
        //如果2是叶子节点并且是false,返回1  如果1 是叶子节点值是true直接返回1
        if((quadTree2.isLeaf && !quadTree2.val) || (quadTree1.isLeaf && quadTree1.val)){
            return quadTree1;
        }
        //到这说明1,2都不是叶子节点了,要递归了
        Node res = new Node(false, false, null, null, null, null);
        res.topLeft = intersect(quadTree1.topLeft, quadTree2.topLeft);
        res.topRight = intersect(quadTree1.topRight, quadTree2.topRight);
        res.bottomLeft = intersect(quadTree1.bottomLeft, quadTree2.bottomLeft);
        res.bottomRight = intersect(quadTree1.bottomRight, quadTree2.bottomRight);
        //合并
        if(res.topLeft.isLeaf && res.topRight.isLeaf
            && res.bottomLeft.isLeaf && res.bottomRight.isLeaf
            && res.topLeft.val == res.topRight.val
            && res.topRight.val == res.bottomLeft.val
            && res.bottomLeft.val == res.bottomRight.val){
            res = res.topLeft;
        }
        return res;
    }
}

其实实际上的代码没多少,一共就几种可能判断。1,2,都是true没必要额外判断一遍,这个属于1是叶子而且true里面。主要就是都不是叶子节点的递归比较麻烦。但是其实逻辑并不是很绕。还是感谢大佬的总结吧。

N叉树的最大高度

题目:给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
题目截图
思路:从二叉到多叉,这就是进步吧?其实我以前也没接触过多叉树,但是感觉应该跟二叉差不多?不知道,我去试试先。
回来了,跟二叉树差不多又有点区别,但是递归是不变的:
/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
    public int maxDepth(Node root) {      
        if(root==null) return 0;
        int max = 0;
        for(int i = 0;i<root.children.size();i++){
            max = Math.max(maxDepth(root.children.get(i)),max);
        }
        return max+1;
    }
}

这个其实也没啥好说的,我测试半天得出正确递归版本,找好递归点就好了,注意逻辑:for循环一遍,但是整体算一层,我之前反正这个+1放循环里了然后得出的答案有点离谱。

数组拆分1

题目:给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。

示例 1:
输入: [1,4,3,2]
输出: 4
解释: n 等于 2, 最大总和为 4 = min(1, 2) + min(3, 4).

提示:

n 是正整数,范围在 [1, 10000].
数组中的元素范围在 [-10000, 10000].

思路:看了半天也没啥好规律,好像就是隔一个留一个。而且留的是较小的那个。比如一个排序数组,只能留下第0个,2个,反正是下标双数的那个(前提是偶数个元素。)我去写代码试试有啥特殊情况。
嗯嗯,没特殊情况,思路是对的。

class Solution {
    public int arrayPairSum(int[] nums) {
        Arrays.sort(nums);
        int res = 0;
        for(int i=0;i<nums.length;i=i+2){
            res += nums[i];

        }
        return res;
    }
}

至今为止不知道考点在哪?难不成是数组排序么?我去试试手写排序能不能性能好点?算了,不折腾了,看了评论有点写不下去了。


image.png

二叉树的坡度

题目:给定一个二叉树,计算整个树的坡度。一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。整个树的坡度就是其所有节点的坡度之和。
题目截图

思路:这道题怎么说呢,读题没太明白,用两次测试案例大概看懂了。就是每个非叶子节点都有坡度。左右都有就是差的绝对值。单有左右就是左右的绝对值。一看这个题目首选的思路就是递归。每一个非叶子节点的坡度累加。我去试着写写代码。

image.png
image.png
很好,我从原则上就理解错了!也怪我审题不清,刚刚我因为是左子节点和右子节点。而且这个demo也比较短,看不出来啥,我只计算了左右两个直系节点,实际上是左节点和和右节点和的差。
image.png

我继续按照这个思路去做。好了,直接贴代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int sum = 0 ;
    public int findTilt(TreeNode root) {
        addAllNode(root);
        return sum;
    }
    public int addAllNode(TreeNode root){
        if(root==null) return 0;       
        int r = addAllNode(root.right);
        int l = addAllNode(root.left);
        sum +=Math.abs(l-r);
        return l + r + root.val;
    }
}

这个题其实只要审对题还是不难的,就是每一个节点的左节点和减去右节点和。存在sum中。然后递归。
今天这篇就这里到这里,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利!

上一篇下一篇

猜你喜欢

热点阅读