Leetcode 151-160刷题笔记(非困难题目)

151.反转字符串的单词

该题目有点类似于字符串的反转,但是该题目需要保证的是字符串内的单词反转后仍然是原先单词,并且格式以“单词1 单词2 单词3”的格式(即需要去除多余空格)

针对于这么频繁的字符串操作我们自然就想到使用的是StringBuilder

刚好他自带了一个reverse()方法用于字符串反转,剩下的部分我们只需要对空格进行处理和内部单词的顺序进行处理。

1.空格部分我是用的计数法,对多次重复出现的空格采取删除。

2.内部单词顺序我采用正常的字符串反转的方法,对其反转,则需要精准截取字符串即可。

    //字符串中的单词替换
    public String reverseWords(String s) {
        //去除头部空格
        s = s.trim();
        //去除尾部空格(从尾部开始查找)
        int end = s.length()-1;
        for(;end>=0; end--) {
            if(s.charAt(end) != ' ') {
                break;
            }
        }
        s = s.substring(0,end + 1);

        //反转整个字符串
        StringBuilder sb = new StringBuilder(s).reverse();
        //针对每个单词在进行反转(此时的单词内部顺序也被反转)
        reverseWord(sb);

        return sb.toString();
    }

    //用于反转单词
    public void reverseWord(StringBuilder sb) {
        int start = 0;
        int end = 0;
        //记录空格数
        int times = 0;
        while(end < sb.length()) {
            if(sb.charAt(end) == ' ') {
                //第一次出现空格
                if(times < 1) {
                    //单词反转(此时end为空格)
                    reverseWord(sb,start,end - 1);
                    times++;
                    //指针移动
                    end++;
                    start = end;
                }else { //删除多余空格
                    sb.deleteCharAt(end);
                }
            }else {
                //空格清零
                times = 0;
                //单词右边界移动
                end++;
            }
        }
        
        if(end > start) {
            //此时end到达右边界,所以需要 - 1
            reverseWord(sb,start,end - 1);
        }
    }

    //反转单个字符
    private void reverseWord(StringBuilder sb, int left, int right) {
        while(left < right) {
            char temp = sb.charAt(left);
            sb.setCharAt(left,sb.charAt(right));
            sb.setCharAt(right,temp);
            left++;
            right--;
        }        
    }

152.乘积最大的子数组

该题目特点就在于他是求乘积最大。

众所周知,使乘积增大有很多中情况,比如正数 * 正数,负数 * 负数。

我们无法的值究竟是哪一种才是最大值,所以我们采用两个dp数组,分别保存最大值和最小值,用于判断。

    //乘积最大子数组(动态规划)
    public int maxProduct(int[] nums) {
        int ans = nums[0];
        //维护一个最大值和最小值的dp数组
        int[] max = new int[nums.length];
        int[] min = new int[nums.length];
        max[0] = nums[0];
        min[0] = nums[0];

        for(int i=1; i<nums.length; i++) {
            max[i] = Math.max(nums[i],Math.max(max[i - 1] * nums[i], min[i - 1] * nums[i]));
            min[i] = Math.min(nums[i],Math.min(max[i - 1] * nums[i], min[i - 1] * nums[i]));

            ans = Math.max(max[i],ans);
        }
        return ans;
    }

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

因为原数组是升序排序数组,经过一定旋转后就改变了模样了。

我们可以采用二分法,对这个旋转数组进行二分查找。

既然选择了二分法那么就需要考虑需要将数组二分。

重点来了:一开始需要想清楚,
1.如果数组整体有序,那么最小值一定在最左边。
2.如果有旋转部分,则最小值一定出现在被旋转的半边。

并且无序半边的话,一定是这种模式 [大1,大2,最小值,小1,小2,小3],所以我们可以将有序半边直接舍去,并且舍弃最左边的高一位

    //寻找旋转数组的最小值(二分法)
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;

        while(left < right) {
            int mid = left + (right - left) / 2;

            //左半边有序
            if(nums[left] <= nums[mid]) {
                if(nums[left] < nums[right]) { //说明是整体有序
                    return nums[left];
                }else { //说明右半部分存在反转,则此时left不为最小值
                    left = mid + 1;
                }
            }else { //左半边无序(最小值一定存在于无序中)
                //舍去最左边的高一位
                left++;
                //舍去有序半边
                right = mid;
            }
        }
        return nums[left];
    }

155.最小栈

题目是常数实现返回栈内最小值。

该题目就是一个对比的思想,用两个栈实现,一个栈用于保存数组,一个栈用于保存栈内最小值(getMin()时直接peek栈顶即可)。

思路是我们在push入栈时,和min栈进行对比,如果比min更小则入min栈,如果比min大则仍旧再入一次min的栈顶元素。

/*
最小栈,要求在时间内检索栈内最小值
 */
class MinStack {
    //记录最小值
    private Stack<Integer> min = new Stack<>();
    private Stack<Integer> stack = new Stack<>();

    /** initialize your data structure here. */
    public MinStack() {

    }

    public void push(int x) {
        //更新最小值
        if(min.isEmpty()) {
            min.push(x);
        }else {
            if(x < min.peek()) {
                min.push(x);
            }else { //无需更新
                min.push(min.peek());
            }
        }

        stack.push(x);
    }

    public void pop() {
        stack.pop();
        min.pop();
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return min.peek();
    }
}

160.相交链表

使用hashSet对一条链表进行保存,访问另一条链表时,如果出现第一次重复则直接返回。

    //求链表交点
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        
        HashSet<ListNode> hashSet = new HashSet<>();
        while(headA != null) {
            hashSet.add(headA);
            headA = headA.next;
        }
        
        while(headB != null) {
            if (hashSet.contains(headB)) {
                return headB;
            }
            headB = headB.next;
        }
        
        return null;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值