刷leetCode算法题+解析(二十九)

检测大写字字母

题目:给定一个单词,你需要判断单词的大写使用是否正确。我们定义,在以下情况时,单词的大写用法是正确的:
全部字母都是大写,比如"USA"。
单词中所有字母都不是大写,比如"leetcode"。
如果单词不只含有一个字母,只有首字母大写, 比如 "Google"。
否则,我们定义这个单词没有正确使用大写字母。

示例 1:
输入: "USA"
输出: True
示例 2:
输入: "FlaG"
输出: False
注意: 输入是由大写和小写拉丁字母组成的非空单词。

思路:这道题简单的让我觉得我理解错题目了?是就一个单词吧?单词之间不能有空格吧?不然不是叫句子么?我先去试试题目是不是我想的这样。
可喜可贺,想法正确:

class Solution {
    public boolean detectCapitalUse(String word) {
        if(word.toLowerCase().equals(word)) return true;
        if(word.toUpperCase().equals(word)) return true;
        String sub = word.substring(0,1).toUpperCase()+word.substring(1).toLowerCase();
        if(sub.equals(word)) return true;
        return false;
    }
} 

果然性能好的人家都是从底层开始写,我这个调用现成大小写api的性能就不那么好了。下面是自己判断的代码:

class Solution {
    public boolean detectCapitalUse(String word) {
        char first = word.charAt(0);int num = 0;
        boolean daxie = first >= 'A' && first <= 'Z' ? true : false;
        for (int i = 1; i < word.length(); i++) {
            if (word.charAt(i) >= 'A' && word.charAt(i) <= 'Z') num ++;
        }
        if (daxie && (num == 0 || num == word.length() - 1)) return true;
        if (!daxie && num == 0) return true;
        return false;
    }
}

最长特殊序列1

题目:给定两个字符串,你需要从这两个字符串中找出最长的特殊序列。最长特殊序列定义如下:该序列为某字符串独有的最长子序列(即不能是其他字符串的子序列)。子序列可以通过删去字符串中的某些字符实现,但不能改变剩余字符的相对顺序。空序列为所有字符串的子序列,任何字符串为其自身的子序列。输入为两个字符串,输出最长特殊序列的长度。如果不存在,则返回 -1。

示例 :
输入: "aba", "cdc"
输出: 3
解析: 最长特殊序列可为 "aba" (或 "cdc")
说明:
两个字符串长度均小于100。
字符串中的字符仅含有 'a'~'z'。

思路:讲真,这个题我认认真真看了三遍,然后现在还怀疑我的理解能力:最长子序列?是不是只要两个字符串完全一样,多的那个就是最长子序列?实在看不明白题目了,我去试试吧
试完了,这个题是来搞笑的,鉴定完毕!

刷leetCode算法题+解析(二十九)_第1张图片
image.png

就当看了个笑话吧,这个系列的2是个会员加锁题,所以除了佩服出题人没话讲,下一题。

二叉搜索树的最小绝对差

题目:给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值。

示例 :
输入:
1

3
/
2
输出:
1
解释:
最小绝对差为1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。
注意: 树中至少有2个节点。

思路:这个题没有进阶要求,脑残思路:遍历节点存list,然后排序元素间最小差值。别管性能咋样起码实现是可以完美实现的。
写的过程中越看二叉搜索树这个题干,越觉得其实可以不这么麻烦,如果是搜索树肯定要保证唯一性和左小右大的天性。一定是有什么方式判断的,但是我这个第一版还是无脑得了。
无脑解完了,简单粗暴:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int getMinimumDifference(TreeNode root) {
        List list = new ArrayList();
        getAllNode(root,list);
        Collections.sort(list);
        int min = Integer.MAX_VALUE;
        for(int i = 0;i list){
        if(root==null) return;
        list.add(root.val);
        getAllNode(root.left,list);
        getAllNode(root.right,list);

    }
}

额,第一版本做出来了可以安心放心的去优化了。刚刚我就说了这个应该是有一定规律的,毕竟这个是二叉查找树。规律就是中间节点在左右节点之间,如果说最小差也会是在中间节点和左右节点之间,所以在方法里设置一个最小值的变量,每次判断一下,遍历的同时就获取了最小差值,如下代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    TreeNode pre = null;
    int res = Integer.MAX_VALUE;
    public int getMinimumDifference(TreeNode root) {
        inOrder(root);
        return res;
    }

    public void inOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        inOrder(root.left);
        if(pre != null) {
            res = Math.min(res, root.val - pre.val);
        }
        pre = root;
        inOrder(root.right);
    }
}

数组中的K-diff数对

题目:给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对。这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字,且两数之差的绝对值是 k.

示例 1:
输入: [3, 1, 4, 1, 5], k = 2
输出: 2
解释: 数组中有两个 2-diff 数对, (1, 3) 和 (3, 5)。
尽管数组中有两个1,但我们只应返回不同的数对的数量。
示例 2:
输入:[1, 2, 3, 4, 5], k = 1
输出: 4
解释: 数组中有四个 1-diff 数对, (1, 2), (2, 3), (3, 4) 和 (4, 5)。
示例 3:
输入: [1, 3, 1, 5, 4], k = 0
输出: 1
解释: 数组中只有一个 0-diff 数对,(1, 1)。
注意:
数对 (i, j) 和数对 (j, i) 被算作同一数对。
数组的长度不超过10,000。
所有输入的整数的范围在 [-1e7, 1e7]。

思路:这个题应该先判断给定的k是不是0,如果是0则判断数组中有多少对相同的数字。如果不是0则将数组中相同的元素去重。毕竟只返回不同的数对的数量。其次的判断其实我个人觉得先排序,然后直接判断数对的另一个是不是存在。。先按照思路写着,其实思路对不对,能不能实现,性能好不好算是三个东西。可能思路对,但是超时不能实现,也可能实现了但是性能贼差。但是想到了先去试试写代码总没错。
嗯,回来了,我每次都觉得把出题人想的挺明白了,显示总能狠狠的打我的脸。气得我脑壳痛!!!!

题目!

刷leetCode算法题+解析(二十九)_第2张图片
测试案例

说好了K是差的绝对值,你给我提交个-1,还能怪我错了??????????没办法,胳膊拗不过大腿,我自己做判断吧。
好了,加个对K的判断通过了,分三种情况,大于0小于0等于0.直接上代码:

class Solution {
    public int findPairs(int[] nums, int k) {
        if(k<0) return 0;
        Set set = new HashSet();
        Arrays.sort(nums);
        if(k==0){
            for(int i=0;i

其实也不复杂,最多O(n)的时间复杂度。小于0直接返回,等于0判断一样的个数。大于0判断一对的另一个是否存在。性能超过八十多人,我其实挺满意了,但是顺便看看排名第一的代码:

class Solution {
    public int findPairs(int[] nums, int k) {
        if(k < 0) return 0;
        Arrays.sort(nums);
        int start = 0;
        int count = 0;
        int prev = 0x7fffffff;
        for (int i = 1; i < nums.length; i++) {
            if(prev == nums[start] || nums[i] - nums[start] > k) {
                start++;
                if (start != i) {
                    i--;
                }
            }else if (nums[i] - nums[start] == k) {
                prev = nums[start];
                start++;
                count++;
            }
        }
        return count;
    }
}

得出的结论就是能不调用api就不调用api,能自己写就自己写。我自己都知道我的性能应该在各种contains判断中消耗巨大,但是架不住方便啊。瞻仰完了大神代码,下一题。

把二叉搜索树转换为累加树

题目:给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。

刷leetCode算法题+解析(二十九)_第3张图片
题目

思路:这里说了是所有大于它的节点值之和。因为是二叉搜索树,所以大于它的节点值的特点就是所有它右边的节点。所以遍历也要按照左->根->右来遍历累加。我去尝试写代码。
emmm。。没写出来,看了题解,原来我跟正确答案就差那么一个思路的转换,只能说看了正确代码恍然大悟,自己写了一两个小时都没思路。直接上代码吧:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private int sum;
    public TreeNode convertBST(TreeNode root) {
        if(root==null) return root;
        convertBST(root.right);
        root.val += sum;
        sum = root.val;
        convertBST(root.left);
        return root;
    }
}

要怎么说?其实逻辑很简单,就是严格按照顺序累加?先加右边的,然后左边的。反正我是没想到,只能争取死记硬背下次一看这个类型能有个思路。

反转字符串2

题目:给定一个字符串和一个整数 k,你需要对从字符串开头算起的每个 2k 个字符的前k个字符进行反转。如果剩余少于 k 个字符,则将剩余的所有全部反转。如果有小于 2k 但大于或等于 k 个字符,则反转前 k 个字符,并将剩余的字符保持原样。

示例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"

要求:

该字符串只包含小写的英文字母。
给定字符串的长度和 k 在[1, 10000]范围内。

思路:额,首先说题目很是复杂啊,看了两三遍才看懂。其次就剩下实现了,反正我个人感觉这种反转字符串的题目。实现和实现的好是完全不同的。而我就是那个能实现但是不见得好的人。接下来去写代码了。
嗯,不出所料的写出来了。不出所料的性能不咋地。这种题目的好出就是不考虑性能的话最笨的办法也可以做出来。直接上代码:

class Solution {
    public String reverseStr(String s, int k) {
        int len = s.length();        
        StringBuffer sb = new StringBuffer();
        int n = 0;
        while(len>2*k){
            sb.append(reverse(s.substring(n*k,k*(n+1))));
            sb.append(s.substring(k*(n+1),k*(n+2)));
            n += 2;
            len = len - k*2;
        }
        if(len

如上面代码,我这里用了一个专门的方法 用来反转字符串。然后根据不同的段(比如是处于k之内,k到2k之间,2k到3k之间判断是正序追加还是倒叙追加。)然后下面的是优化一点点的版本:

class Solution {
    public String reverseStr(String s, int k) {
        int len = s.length();        
        StringBuffer sb = new StringBuffer();
        int i = 0;
        while(i*k

其实思路没变化,只不过逻辑更加清晰了而已。其实在写的过程中隐约想起来好像做过类似的题目,当时好像是倒叙再倒叙就正了。。不过放在这个题目上还没想好要怎么用。我还是直接看题解吧。
大概上的性能我这里的反转是返回新字符串。而性能好的是在原字符串的基础上反转的。剩下的我这里的反转是从头到尾的遍历。人家的反转是前后位置交换。只能说一看就懂,自己写不出。附上代码瞻仰:

class Solution {
    public String reverseStr(String s, int k) {
        char[] ch = s.toCharArray();
        int n = 0;
        for(int i = 0;i

二叉树的直径

题目:给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。
刷leetCode算法题+解析(二十九)_第4张图片
题目截图

思路:关于这个题是题目,我还不是很理解,是不是说树左右两边最深度的和就是直径?因为接触的少也不知道理解的对不对,我先去写代码试试。
嗯,写完回来了,是我想的太简单了。不仅仅是根节点左右两边的深度和。上个图吧,如图所示红色部分才是直径。所以这个是要递归套递归的,每一个节点都可能是最长直径的根节点。(不要吐槽我话的不标准,能对付看就行了。这个树是根据测试案例画的)

刷leetCode算法题+解析(二十九)_第5张图片
image.png

我简直了,,,,对付递归+递归的做出来了,性能只超过百分之十二???哎呦,心疼自己。贴上第一版本代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int diameterOfBinaryTree(TreeNode root) {
        int max = 0;
        if(root!=null){
            int left = treeD(root.left,0);
            int right = treeD(root.right,0);
            if(right>left){
                return Math.max(left+right,diameterOfBinaryTree(root.right));
            }else{
                return Math.max(left+right,diameterOfBinaryTree(root.left));
            }
        }
        return 0;
        
    }
    //层数,边数比层数少1
    public int treeD(TreeNode root,int d){
        if(root==null) return d;
        return 1+Math.max(treeD(root.left,d),treeD(root.right,d));
    }
}

其实我感觉代码逻辑很清晰,无论是求深度还是选取不同节点当中心点,天晓得大神的代码怎么写的,我自己又看了看,觉得可能是方法中的递归不对。直接看看排行第一的代码吧。
看完回来了,几行代码,改一点不行,改一句不行。本来是看了眼知道思路就努力自己做的,结果测测改改,最后完成版和人家的一样一样的。中间我不想用left,right表示,直接用方法,结果max中和返回值中都用到了,完美的超时了,所以改成这样。除了膜拜还能说什么?

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private int max = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        treeD(root);
        return max;
        
    }
    //层数,边数比层数少1
    public int treeD(TreeNode root){
        if(root==null) return 0;
        int left = treeD(root.left);
        int right = treeD(root.right);
        max = Math.max(left+right,max);
        //这个返回值用于上面的比较
        return 1+Math.max(left,right);
    }
}

这边笔记就记录到这里吧,之前因为周末整整玩了两天,所以决定这几天要补回来。一天五道题算,emmmm。。继续刷题了,如果稍微帮到你了记得点个喜欢点个关注。也祝大家工作顺顺利利!

你可能感兴趣的:(刷leetCode算法题+解析(二十九))