LeetCode_20天算法刷题计划

这篇博客详细记录了作者从零开始学习算法的过程,重点介绍了二分查找及其应用,如搜索插入位置和找第一个错误的版本。随后,作者探讨了双指针在解决有序数组平方、数组旋转、移动零、两数之和等题目的巧妙运用。最后,涉及字符串反转和链表操作,展示了双指针和迭代在解决这些问题上的威力。
摘要由CSDN通过智能技术生成


前言

零基础小白记录一下算法学习过程(虽然记录晚了)。


第一天:二分查找

  1. 二分查找
    网址:https://leetcode.cn/problems/binary-search/

    给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的target,如果目标值存在返回下标,否则返回 -1。

    示例1:
    输入: nums = [-1,0,3,5,9,12], target = 9
    输出: 4
    解释: 9 出现在 nums 中并且下标为 4
    示例2:
    输入: nums = [-1,0,3,5,9,12], target = 2
    输出: -1
    解释: 2 不存在 nums 中因此返回 -1

    class Solution {
        public int search(int[] nums, int target) {
            int left = 0,right = nums.length - 1;
            while(left <= right){
                int pivot = (left + right) / 2;
                if(nums[pivot] == target){
                    return pivot;
                }else if(nums[pivot] < target){
                    left = pivot + 1;
                }else if(nums[pivot] > target){
                    right = pivot - 1;
                }
            }
            return -1;
        }
    }
    
  2. 第一个错误的版本
    网址:https://leetcode.cn/problems/first-bad-version/

    你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

    假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。

    你可以通过调用bool isBadVersion(version)接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

    示例1:
    输入:n = 5, bad = 4
    输出:4
    示例2:
    输入:n = 1, bad = 1
    输出:1

    public class Solution extends VersionControl {
        public int firstBadVersion(int n) {
            int left = 1, right = n;
            while (left < right) { // 循环直至区间左右端点相同
                int mid = left + (right - left) / 2; // 防止计算时溢出
                if (isBadVersion(mid)) {
                    right = mid; // 答案在区间 [left, mid] 中
                } else {
                    left = mid + 1; // 答案在区间 [mid+1, right] 中
                }
            }
            // 此时有 left == right,区间缩为一个点,即为答案
            return left;
        }
    }
    
  3. 搜索插入位置
    网址:https://leetcode.cn/problems/search-insert-position/

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

    请必须使用时间复杂度为 O(log n) 的算法。

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

    class Solution {
        public int searchInsert(int[] nums, int target) {
            if(nums[0] > target){return 0;}
            if(nums[nums.length - 1] < target){return nums.length;}
            int left = 0;
            int right = nums.length - 1;
            while(left < right){
                int pivot = (left + right) / 2;
                if(nums[pivot] < target){
                    left = pivot + 1;
                }else if(nums[pivot] > target){
                    right = pivot;
                }else{
                    return pivot;
                }
            }
            return left;
        }
    }
    
  • 感觉自己写的还是不那么好,用两个if判断跳过了特殊情况,后来再看看怎么解决吧。

第二天:双指针(一)

  1. 有序数组的平方
    网址:https://leetcode.cn/problems/squares-of-a-sorted-array/

    给你一个按非递减顺序排序的整数数组 nums,返回 每个数字的平方组成的新数组,要求也按非递减顺序排序。

    示例1:
    输入:nums = [-4,-1,0,3,10]
    输出:[0,1,9,16,100]

    思路:挺简单的,将数组的各元素先进行平方,在经过冒泡排序进行排序。

    class Solution {
        public int[] sortedSquares(int[] nums) {
            for(int i = 0;i < nums.length;i++){
                nums[i] = nums[i] * nums[i];
            }
            maopao(nums);
            return nums;
        }
        public void maopao(int[] a){
            for (int i = 0; i < a.length - 1; i++) {
                for (int j = 0; j < a.length - 1 - i; j++) {
                    if (a[j] > a[j + 1]) {
                        int temp = a[j];
                        a[j] = a[j + 1];
                        a[j + 1] = temp;
                    }
                }
            }
        }
    }
    
  2. 轮转数组
    网址:https://leetcode.cn/problems/rotate-array/
    给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
    思路:感觉不好想可能就是这个取余的操作吧。

    示例1:
    输入: nums = [1,2,3,4,5,6,7], k = 3
    输出: [5,6,7,1,2,3,4]
    解释:
    向右轮转 1 步: [7,1,2,3,4,5,6]
    向右轮转 2 步: [6,7,1,2,3,4,5]
    向右轮转 3 步: [5,6,7,1,2,3,4]
    示例2:
    输入:nums = [-1,-100,3,99], k = 2
    输出:[3,99,-1,-100]
    解释:
    向右轮转 1 步: [99,-1,-100,3]
    向右轮转 2 步: [3,99,-1,-100]

    思路:感觉还是比较简单的吧。

    class Solution {
        public void rotate(int[] nums, int k) {
            if(nums.length == 1){
                nums = nums;
            }else{
                k = k % nums.length;
                int[] temp = new int[k];
                for(int i = 0;i < temp.length;i++){
                    temp[i] = nums[i + nums.length - k];
                }
                for(int i = nums.length - 1;i >= k;i--){
                    nums[i] = nums[i - k];
                }
                for(int i = 0;i < k;i++){
                    nums[i] = temp[i];
                }
            }
        }
    }
    

第三天:双指针(二)

  1. 移动零
    网址:https://leetcode.cn/problems/move-zeroes/

    给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

    请注意 ,必须在不复制数组的情况下原地对数组进行操作。

    示例1:
    输入: nums = [0,1,0,3,12]
    输出: [1,3,12,0,0]
    示例2:
    输入: nums = [0]
    输出: [0]

    class Solution {
        public void moveZeroes(int[] nums) {
            for(int i = 0;i < nums.length - 1;i++){
                for(int j = 0;j < nums.length - 1 - i;j++){
                    if(nums[j] == 0){
                        int temp = nums[j];
                        nums[j] = nums[j+1];
                        nums[j+1] = temp;
                    }
                }
            }
        }
    }
    
  2. 两数之和 II - 输入有序数组
    网址:https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/

    给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

    以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

    你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

    你所设计的解决方案必须只使用常量级的额外空间。

    示例1:
    输入:numbers = [2,7,11,15], target = 9
    输出:[1,2]
    解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
    示例2:
    输入:numbers = [2,3,4], target = 6
    输出:[1,3]
    解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。
    示例3:
    输入:numbers = [-1,0], target = -1
    输出:[1,2]
    解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

    思路:主要还是双指针的思想吧。

    class Solution {
        public int[] twoSum(int[] numbers, int target) {
            int[] ans = new int[2];
            int i = 0;
            int j = numbers.length - 1;
            while(i < j){
                if((numbers[i] + numbers[j]) == target){
                    ans[0] = i + 1;
                    ans[1] = j + 1;
                    return ans;
                }else if((numbers[i] + numbers[j]) < target){
                    i++;
                }else if((numbers[i] + numbers[j]) > target){
                    j--;
                }
            }
            return ans;
        }
    }
    

第四天:双指针(三)

  1. 反转字符串

    网址:https://leetcode.cn/problems/reverse-string/

    编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

    不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

    示例 1:
    输入:s = [“h”,“e”,“l”,“l”,“o”]
    输出:[“o”,“l”,“l”,“e”,“h”]
    示例 2:
    输入:s = [“H”,“a”,“n”,“n”,“a”,“h”]
    输出:[“h”,“a”,“n”,“n”,“a”,“H”]

    思路:主要还是双指针吧。

    class Solution {
        public void reverseString(char[] s) {
            int i = 0,j = s.length - 1;
            while(i < j){
                char temp = s[i];
                s[i] = s[j];
                s[j] = temp;
                i++;
                j--;
            }
        }
    }
    
  2. 反转字符串中的单词 III
    网址:https://leetcode.cn/problems/reverse-words-in-a-string-iii/
    给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

    示例 1:
    输入:s = “Let’s take LeetCode contest”
    输出:“s’teL ekat edoCteeL tsetnoc”
    示例 2:
    输入: s = “God Ding”
    输出:“doG gniD”

    class Solution {
        public String reverseWords(String s) {
            String[] temp = s.split(" ");
            for(int i = 0;i < temp.length;i++){
                String a="";
                for(int j = temp[i].length() - 1;j >= 0;j--){
                    a+=temp[i].charAt(j);
                }
                temp[i] = a;
            }
            String ans="";
            for(int i = 0;i < temp.length;i++){
                ans+=temp[i];
                if(i == temp.length - 1){
                    break;
                }else{
                    ans+=" ";
                }
            }
            return ans;
        }
    }
    

第五天:双指针(四)

  1. 链表的中间结点
    网址:https://leetcode.cn/problems/middle-of-the-linked-list/

    给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

    示例 1:
    输入:[1,2,3,4,5]
    输出:此列表中的结点 3 (序列化形式:[3,4,5])
    返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
    注意,我们返回了一个 ListNode 类型的对象 ans,这样:
    ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
    示例 2:
    输入:[1,2,3,4,5,6]
    输出:此列表中的结点 4 (序列化形式:[4,5,6])
    由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

    class Solution {
        public ListNode middleNode(ListNode head) {
            ListNode i = head;
            ListNode j = head;
            while(j != null && j.next != null){
                i = i.next;
                j = j.next.next;
            }
            return i;
        }
    }
    
  2. 删除链表的倒数第 N 个结点
    网址:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

    给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
    在这里插入图片描述

    示例 1:
    输入:head = [1,2,3,4,5], n = 2
    输出:[1,2,3,5]
    示例 2:
    输入:head = [1], n = 1
    输出:[]
    示例 3:
    输入:head = [1,2], n = 1
    输出:[1]

    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            if(head.next == null){return head.next;}
            ListNode temp = new ListNode(0,head);
            ListNode i = temp;
            ListNode j = head;
            for(int c = 0;c < n;c++){
                j = j.next;
            }
            while(j != null){
                i = i.next;
                j = j.next;
            }
            i.next = i.next.next;
            return temp.next;
        }
    }
    

总结

慢慢写吧,认识到自己很菜的事实了😭。思路还得想想怎么整理一下。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值