java学习之路

leetCode进阶算法题+解析(二十四)

2020-03-16  本文已影响0人  唯有努力不欺人丶

翻转字符串里的单词

题目:给定一个字符串,逐个翻转字符串中的每个单词。

示例 1:
输入: "the sky is blue"
输出: "blue is sky the"
示例 2:
输入: " hello world! "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
说明:
无空格字符构成一个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
进阶:
请选用 C 语言的用户尝试使用 O(1) 额外空间复杂度的原地解法。

思路:讲真,这个题像是初级难度的啊,进阶要求是C语言的才有的,,我是java,哈哈。然后单纯的实现其实真的很简单,trim去前后空格,然后空格拆分字符串,然后双指针调换位置,然后stringBuffer加上。就酱,我去实现下
好了,思路没问题,而且很简单,性能超过百分之九十八,我都不敢去看评论了,恐怕再说我不应该用啥。。我先贴代码:

class Solution {
    public String reverseWords(String s) {
        s = s.trim();
        String[] arr = s.split(" ");
        StringBuffer sb = new StringBuffer();
        for(int i = arr.length-1;i>=0;i--){
            if(arr[i].equals(" ") || arr[i].equals("") ) continue;
            sb.append(arr[i]+" ");
        }
        return sb.toString().trim();
    }
}

算了,伸头一刀缩头一刀,我去瞅瞅评论说啥了。
额,评论没说啥啊,而且性能排行第一的代码也是这个套路,所以这个题就过了吧!

寻找旋转排序数组中的最小值

题目:假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。请找出其中最小的元素。你可以假设数组中不存在重复元素。

示例 1:
输入: [3,4,5,1,2]
输出: 1
示例 2:
输入: [4,5,6,7,0,1,2]
输出: 0

思路:这个题我感觉题目肯定是少条件了。不然不能是中等难度啊,不就是一个遍历的事么?应该是时间复杂度logn?常量级是不可能的,,我去按照我想的时间复杂度做了。
第一版本出来了,我先贴出来:

class Solution {
    public int findMin(int[] nums) {
        int l = 0;
        int r = nums.length-1;
        while(l<r){
            if(nums[l]<nums[r]) return nums[l];
            if(nums[l]>nums[l+1]) return nums[l+1];
            if(nums[r]<nums[r-1]) return nums[r];
            l++;
            r--;
        }
        return nums[0];
    }
}

这个时间复杂度是n。不太满足我的要求,我再去试试logn实现的。
好了,二分法实现了,我贴下代码:‘

class Solution {
    public int findMin(int[] nums) {
        if(nums.length == 1) return nums[0];
        //说明已经是升序了
        if(nums[0]<nums[nums.length-1]) return nums[0];
        int l = 0;
        int r = nums.length-1;
        while(l<r){
            int mid = (r-l)/2+l;
            if(nums[mid]<nums[r]){//后半段是排好序的。说明旋转点在前半段
                r = mid;
            }else if(nums[mid]>nums[r]){//旋转点在后半段
                l = mid +1;
            }else{
                return nums[mid];
            }
        }
        return nums[l];
    }
}

然后这道题就这样了,不算难,难点就是二分法区间了。没啥好说的,多看看就好了,直接下一题了。

乘积最大子序列

题目:给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。

示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

思路:这道题怎么说呢,乍一看我甚至想到了动态规划,但是仔细瞅了瞅,其实逻辑好处理多了。也可以用dp。第一个数作为开始值,挨个和后面乘,保存其中的最大乘积,第二个数开始,挨个和后面乘,保存最大乘积,反正取最大的就行。我去实现啦。
哎,我自己实现了,然后性能贼可怜,但是我还是要发出来,毕竟是自己想出来的:

class Solution {
    public int maxProduct(int[] nums) {
        int max = Integer.MIN_VALUE;
        for(int i = 0;i<nums.length;i++){
            int count = nums[i];
            max = Math.max(max,count);
            for(int j = i+1;j<nums.length;j++){
                count *= nums[j];
                 max = Math.max(max,count);
            }
        }
        return max;
    }
}

咳咳,无脑但是一看就懂,我觉得挺好的,但是性能太不给力啊~~~
其实有这个感觉,毕竟做了很多无用功,我去看看怎么能优化一下。
好了,接下来去看性能排行第一的代码了!对,我凭实力优化不出来了。。。膜拜大佬吧

class Solution {
    public int maxProduct(int[] nums) {
        /*求最大值,看被0拆分的各个子数组的最大值
        1.负数为偶数:全部乘积
        2.负数为奇数:最左或最右的负数不在内,从左到右和从右到左分别计算,求最大
        3.存在0,则从1重新开始
        */
        int m=1;
        int max=nums[0];
        for(int num:nums){
            m=m*num;
            max=Math.max(max,m);
            if(num==0){
                m=1;
            }
        }
        m=1;
        for(int i=nums.length-1;i>=0;i--){
            m=m*nums[i];
            max=Math.max(max,m);
            if(nums[i]==0){
                m=1;
            }
        }
        return max;
    }
}

这个思路怎么说呢,代码复杂了点,因为两遍循环。但是比我的n方的时间复杂度好太多。。。我只能说记住了,下次争取自己写也这样写。
今天的笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注哟~!然后顺便祝大家工作顺顺利利!生活健健康康!

上一篇下一篇

猜你喜欢

热点阅读