Plantre Plantre
首页
  • 算法

    • 查找
    • 排序
  • 力扣

    • 排序
技术
硬件
逆向
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

plantre

一个后端开发者
首页
  • 算法

    • 查找
    • 排序
  • 力扣

    • 排序
技术
硬件
逆向
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 计算机组成原理

  • 操作系统

  • 计算机网络

  • 设计模式

  • Java

  • Spring

  • SpringCloud

  • MySQL

  • Redis

  • 分布式

  • Zookeeper

  • Dubbo

  • Kafka

  • 数据结构

  • 算法

  • OJ

    • 自定义
    • 排序
    • 位运算
    • 二分查找
    • 递归
    • 双指针(逆向,快慢)
      • 滑动窗口
      • 辅助栈
      • 贪心
      • 回溯
      • 动态规划
      • 二叉树
      • DFS
      • 拼接&拆分
      • 模拟
      • 工业实现原理
      • 数学
      • 字符串
    • 从道家哲学看计算机?
    • 后端
    • OJ
    plantre
    2025-06-11
    目录

    双指针(逆向,快慢)

    # 165. 比较版本号 - 力扣(LeetCode) (opens new window)

    双指针

    class Solution {
        public int compareVersion(String version1, String version2) {
            int i = 0, j = 0;
            int n = version1.length(), m = version2.length();
            while (i < n || j < m) {
                int num1 = 0, num2 = 0;
                // 从左到右,每新增一位,就把原来的值整体*10+当前位的值
                while (i < n && version1.charAt(i) != '.') {
                    num1 = num1 * 10 + (version1.charAt(i) - '0');
                    i++;
                }
                while (j < m && version2.charAt(j) != '.') {
                    num2 = num2 * 10 + (version2.charAt(j) - '0');
                    j++;
                }
                // 比较当前修订号
                if (num1 > num2) return 1;
                else if (num1 < num2) return -1;
                // 跳过点号,进入下一修订号
                i++;
                j++;
            }
            return 0;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    分割

    class Solution {
        public int compareVersion(String version1, String version2) {
            String[] v1 = version1.split("\\.");
            String[] v2 = version2.split("\\.");
            int maxLen = Math.max(v1.length, v2.length);
            for (int i = 0; i < maxLen; i++) {
                int num1 = i < v1.length ? Integer.parseInt(v1[i]) : 0;
                int num2 = i < v2.length ? Integer.parseInt(v2[i]) : 0;
                if (num1 > num2) return 1;
                else if (num1 < num2) return -1;
            }
            return 0;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # 202. 快乐数 - 力扣(LeetCode) (opens new window)

    class Solution {
        public boolean isHappy(int n) {
            int slow = n;
            int fast = getNext(n);
            while (fast != 1 && slow != fast) {
                slow = getNext(slow);
                fast = getNext(getNext(fast));
            }
            return fast == 1;
        }
    
        public int getNext(int n){
            int sum=0;
            while (n > 0) {
                int d = n % 10;
                n = n / 10;
                sum += d * d;
            }
            return sum;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    # 141. 环形链表 - 力扣(LeetCode) (opens new window)

    public class Solution {
        public boolean hasCycle(ListNode head) {
            if (head == null) return false;
            ListNode fast,slow;
            fast = slow = head;
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
                if(fast == slow) return true;
            }
            return false;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 142. 环形链表 II - 力扣(LeetCode) (opens new window)

    public class Solution {
        public ListNode detectCycle(ListNode head) {
            ListNode fast,slow;
            fast = slow = head;
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
                if(fast == slow) break;
            }
            if(fast == null || fast.next == null){
                return null;
            }
            slow = head;
            while(slow != fast){
                fast = fast.next;
                slow = slow.next;
            }
            return slow;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    # 160. 相交链表 - 力扣(LeetCode) (opens new window)

    设链表 A 独有部分长度为 a,链表 B 独有部分长度为 b,公共部分长度为 c。
    指针 pA 遍历路径:a + c + b
    指针 pB 遍历路径:b + c + a
    路径长度相等,因此若存在交点,指针必在 c 的起始点相遇
    
    1
    2
    3
    4
    public class Solution {
        public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            ListNode B = headB, A = headA;
            while (A != B) {
                A = A == null ? headB : A.next;
                B = B == null ? headA : B.next;
            }
            return A;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    # 21. 合并两个有序链表 - 力扣(LeetCode) (opens new window)

    class Solution {
        public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dum = new ListNode(0), cur = dum;
            while (list1 != null && list2 != null) {
                if (list1.val < list2.val) {
                    cur.next = list1;
                    list1 = list1.next;
                }
                else {
                    cur.next = list2;
                    list2 = list2.next;
                }
                cur = cur.next;
            }
            cur.next = list1 != null ? list1 : list2;
            return dum.next;
    }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    # 88. 合并两个有序数组 - 力扣(LeetCode) (opens new window)

    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            int p1 = 0, p2 = 0;
            int[] sorted = new int[m + n];
            int cur;
            while (p1 < m || p2 < n) {
                //p1指针遍历完
                if (p1 == m) {
                    cur = nums2[p2++];
                    //p2指针遍历完
                } else if (p2 == n) {
                    cur = nums1[p1++];
                } else if (nums1[p1] < nums2[p2]) {
                    cur = nums1[p1++];
                } else {
                    cur = nums2[p2++];
                }
                sorted[p1 + p2 - 1] = cur;
            }
            for (int i = 0; i != m + n; ++i ) {
                nums1[i] = sorted[i];
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    倒序双指针

    //倒序双指针
    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            int p1 = m - 1, p2 = n - 1;
            int tail = m + n - 1;
            int cur;
            while (p1 >= 0 || p2>= 0) {
                if (p1 == -1) {
                    cur = nums2[p2--];
                } else if (p2 == -1) {
                    cur = nums1[p1--];
                } else if (nums1[p1] > nums2[p2]) {
                    cur = nums1[p1--];
                } else {
                    cur = nums2[p2--];
                }
                nums1[tail--] = cur;
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    # 86. 分隔链表 - 力扣(LeetCode) (opens new window)

    class Solution {
        public ListNode partition(ListNode head, int x) {
            ListNode small=new ListNode(0);
            ListNode smallHead=small;
            ListNode large=new ListNode(0);
            ListNode largeHead=large;
            while(head!=null){
                if(head.val<x){
                    small.next=head;
                    small=small.next;
                }else{
                    large.next=head;
                    large=large.next;
                }
                head=head.next;
            }
            large.next=null;
            small.next=largeHead.next;
            return smallHead.next;                
         }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    # 92. 反转链表 II - 力扣(LeetCode) (opens new window)

    双指针+头插法+哑节点

    class Solution {
        public ListNode reverseBetween(ListNode head, int left, int right) {
            ListNode dummyHead = new ListNode(0);
            dummyHead.next=head;
    
            ListNode g=dummyHead;
            ListNode p=dummyHead.next;
    
            for(int step = 0;step < left - 1;step++){
                g = g.next;
                p = p.next;          
            }
    
            for(int i = 0;i < right - left ;i++){
                ListNode removed = p.next;
                p.next = p.next.next;
                removed.next = g.next;
                g.next = removed;
            }
    
            return dummyHead.next;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    # 15. 三数之和 - 力扣(LeetCode) (opens new window)

    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            Arrays.sort(nums);
            List<List<Integer>> res = new ArrayList<>();
            for (int k = 0; k < nums.length - 2; k++) {
                //当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即 3 个元素都大于 0 ,在此固定指针 k 之后不可能再找到结果了
                if (nums[k] > 0) break;
                //当 k > 0且nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合
                if (k > 0 && nums[k] == nums[k - 1]) continue;
                int i = k + 1, j = nums.length - 1;
                while (i < j) {
                    int sum = nums[k] + nums[i] + nums[j];
                    if (sum < 0) {
                        //当s < 0时,i += 1并跳过所有重复的nums[i];
                        i++;
                        while(i < j && nums[i] == nums[i-1]) {
                            i++;
                        }
                    } else if (sum > 0) {
                        //当s > 0时,j -= 1并跳过所有重复的nums[j];
                        j--;
                        while(i < j && nums[j] == nums[j+1]) {
                            j--;
                        }
                    } else {
                        //当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合
                        res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
                        i++;
                        while(i < j && nums[i] == nums[i-1]) {
                            i++;
                        }
                        j--;
                        while(i < j && nums[j] == nums[j+1]) {
                            j--;
                        }
                    }
                }
            }
            return res;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41

    # 75. 颜色分类 - 力扣(LeetCode) (opens new window)

    class Solution {
        public void sortColors(int[] nums) {
            int p0 = 0, p2 = nums.length - 1;
            for (int i = 0; i <= p2; i++) {
                // 如果遍历到2,将当前位置和p2交换位置
                // 注意:当我们找到2时,我们需要不断地将其与nums[p2]进行交换,直到新的nums[i]不为2
                while (i <= p2 && nums[i] == 2) {
                    int temp = nums[i];
                    nums[i] = nums[p2];
                    nums[p2] = temp;
                    --p2;
                }
                if (nums[i] == 0) {
                    int temp = nums[i];
                    nums[i] = nums[p0];
                    nums[p0] = temp;
                    ++p0;
                }
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    # 977. 有序数组的平方 - 力扣(LeetCode) (opens new window)

    class Solution {
        public int[] sortedSquares(int[] nums) {
            int[] res = new int[nums.length];
            int left = 0, right = nums.length - 1,cur = nums.length - 1;
            while (left <= right) {
                if (Math.abs(nums[left]) >= Math.abs(nums[right])) {         
                    res[cur--] = nums[left] * nums[left];
                    left++;
                } else {
                    res[cur--] = nums[right] * nums[right];
                    right--;
                }
            }
            return res;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    # 11. 盛最多水的容器 - 力扣(LeetCode) (opens new window)

    class Solution {
        public int maxArea(int[] height) {
            int res = 0;
            int left = 0, right = height.length - 1;
            while (left <= right) {
                if (height[left] >= height[right]) {         
                    res = Math.max(res,height[right] * (right - left));
                    right--;
                } else {
                    res = Math.max(res,height[left] * (right - left));
                    left++;
                }
            }
            return res;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    # 快慢指针

    # 143. 重排链表 - 力扣(LeetCode) (opens new window)

    class Solution {
        public void reorderList(ListNode head) {
            ListNode slow = head, fast = head;
            while (fast.next != null && fast.next.next != null) {
                slow = slow.next;
                fast = fast.next.next;
            }
            ListNode l1 = head, l2 = slow.next;
            slow.next = null;
            l2 = reverseList(l2);
            mergeList(l1, l2);
        }
    
        ListNode reverseList(ListNode head) { 
            // 前驱,当前
            ListNode prev = null, curr = head;
            while (curr != null) { 
                ListNode nextTemp = curr.next;
                curr.next = prev;
                prev = curr;
                curr = nextTemp;
            }
            return prev;
        }
    
        void mergeList(ListNode l1, ListNode l2) {
            while (l1 != null && l2 != null) {
                ListNode l1Next = l1.next; // 保存原后继
                ListNode l2Next = l2.next;
                l1.next = l2;
                l2.next = l1Next;
                l1 = l1Next;
                l2 = l2Next;
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    # 19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) (opens new window)

    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            // 创建虚拟头节点,简化边界处理(如删除头节点)
            ListNode dummy = new ListNode(0);
            dummy.next = head;
            ListNode fast = dummy;
            ListNode slow = dummy;
            // 快指针先移动 n+1 步(使快慢指针间距为 n+1)
            for (int i = 0; i <= n; i++) {
                fast = fast.next;
            }
            // 同时移动快慢指针,直到快指针到达链表末尾
             while (fast != null) {
                fast = fast.next;
                slow = slow.next;
            }
            // 此时 slow 指向待删除节点的前驱节点
            slow.next = slow.next.next; // 删除目标节点
            return dummy.next; // 返回新链表头节点
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    # 234. 回文链表 - 力扣(LeetCode) (opens new window)

    双指针 + 反转后半链表(最优解)

    class Solution {
        public boolean isPalindrome(ListNode head) {
            // 空链表或单节点
            if (head == null || head.next == null) return true;
            // 1. 快慢指针找中点
            ListNode slow = head, fast = head;
            while (fast.next != null && fast.next.next != null) {
                slow = slow.next;
                fast = fast.next.next;
            }
            // 2. 反转后半部分(从 slow.next 开始)
            ListNode secondHalf = reverse(slow.next);
            ListNode firstHalf = head;
            // 3. 比较两部分
            ListNode p = secondHalf;
            boolean isPalin = true;
            while (p != null) {
                if (firstHalf.val != p.val) {
                    isPalin = false;
                    break;
                }
                firstHalf = firstHalf.next;
                p = p.next;
            }
            // 4. 恢复链表(可选)
            slow.next = reverse(secondHalf);
            return isPalin;
        }
    
        private ListNode reverse(ListNode head) {
            ListNode prev = null, curr = head;
            while (curr != null) {
                ListNode next = curr.next;
                curr.next = prev;
                prev = curr;
                curr = next;
            }
            return prev;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40

    边找中点边反转前半部分

    class Solution {
        public boolean isPalindrome(ListNode head) {
            if (head == null || head.next == null) return true;
            ListNode slow = head, fast = head;
             // 用于反转前半部分
            ListNode prev = null;
             // 1. 快指针移动时反转慢指针路径
            while (fast != null && fast.next != null) {
                fast = fast.next.next;
                ListNode next = slow.next;
                slow.next = prev;
                prev = slow;
                slow = next;
            }
             // 2. 处理奇数节点:跳过中间节点
            if (fast != null) slow = slow.next;
            // 3. 比较反转后的前半部分(prev)和后半部分(slow)
            while (slow != null) {
                if (prev.val != slow.val) return false;
                prev = prev.next;
                slow = slow.next;
            }
            return true;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    栈(空间 O(n),非进阶)

    class Solution {
        public boolean isPalindrome(ListNode head) {
            Deque<Integer> stack = new LinkedList<>();
            ListNode curr = head;
            // 所有节点值入栈
            while (curr != null) {
                stack.push(curr.val);
                curr = curr.next;
            }
            // 出栈与链表顺序比较
            curr = head;
            while (!stack.isEmpty()) {
                if (stack.pop() != curr.val) return false;
                curr = curr.next;
            }
            return true;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    # 283. 移动零 - 力扣(LeetCode) (opens new window)

    class Solution {
        public void moveZeroes(int[] nums) {
            int slow = 0;
            for (int fast = 0; fast < nums.length; fast++) {
                if (nums[fast] != 0) {
                     // 交换非零元素到慢指针位置
                    int temp = nums[slow];
                    nums[slow] = nums[fast];
                    nums[fast] = temp;
                    slow++;
                }
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    覆盖+补零法:

    1. 快指针覆盖慢指针:将非零元素直接前移。
    2. 末尾补零:遍历结束后将慢指针后的位置置零
    class Solution {
        public void moveZeroes(int[] nums) {
            int slow = 0;
            for (int fast = 0; fast < nums.length; fast++) {
                if (nums[fast] != 0) {
                    // 直接覆盖,无需交换
                    nums[slow] = nums[fast]; 
                    slow++;
                }
            }
            // 末尾补零
            while (slow < nums.length) {
                nums[slow] = 0;
                slow++;
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    # LCR 140. 训练计划 II - 力扣(LeetCode) (opens new window)

    class Solution {
        public ListNode trainingPlan(ListNode head, int cnt) {
            ListNode fast = head, slow = head;
            // 快指针先走 cnt 步
            for (int i = 0; i < cnt; i++) { 
                if (fast == null) return null;
                fast = fast.next;
            }
            // 同步移动fast到末尾
            while (fast != null) {
                fast = fast.next;
                slow = slow.next;
            }
            // slow 指向倒数第 cnt 个节点
            return slow;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    # 尾部双指针

    # 415. 字符串相加 - 力扣(LeetCode) (opens new window)

    class Solution {
        public String addStrings(String num1, String num2) {
            StringBuilder sb = new StringBuilder();
            int i = num1.length() - 1, j = num2.length() - 1;
            int carry = 0;
            while (i >= 0 || j >= 0 || carry != 0) { 
                int a = (i >= 0) ? num1.charAt(i--) - '0' : 0; // 字符转数字,指针左移
                int b = (j >= 0) ? num2.charAt(j--) - '0' : 0;
                int sum = a + b + carry;
                carry = sum / 10;
                sb.append(sum % 10);
            }
            return sb.reverse().toString();
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 151. 反转字符串中的单词 - 力扣(LeetCode) (opens new window)

    class Solution {
        public String reverseWords(String s) {
            // 删除首尾空格
            s = s.trim(); 
            // j指向当前单词末尾,i用于扫描
            int j = s.length() - 1, i = j;
            StringBuilder res = new StringBuilder();
            while (i >= 0) {
                // 向前扫描,找到单词起始位置前的空格
                while (i >= 0 && s.charAt(i) != ' ') i--;
                // 截取单词并追加(注意添加空格分隔符)
                res.append(s.substring(i + 1, j + 1) + " ");
                // 跳过单词间多余空格
                while (i >= 0 && s.charAt(i) == ' ') i--;
                // j更新为下一个单词的末尾位置
                j = i;
            }
            return res.toString().trim();
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    常规分割

    class Solution {
        public String reverseWords(String s) {
            // 1. 移除多余空格(首尾、中间连续空格)
            StringBuilder sb = removeExtraSpaces(s);
             // 2. 反转整个字符串
            reverse(sb, 0, sb.length() - 1);
            // 3. 反转每个单词
            reverseEachWord(sb);
            return sb.toString();
        }
    
        private StringBuilder removeExtraSpaces(String s) {
            int start = 0, end = s.length() - 1;
            // 跳过首尾空格
            while (start <= end && s.charAt(start) == ' ') start++;
            while (end >= start && s.charAt(end) == ' ') end--;
            StringBuilder sb = new StringBuilder();
            while (start <= end) {
                char c = s.charAt(start);
                // 只保留非空格或上一个字符非空格的空格(避免连续空格)
                if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {
                    sb.append(c);
                }
                start++;
            }
            return sb;
        }
    
        private void reverse(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--;
            }
        }
    
        private void reverseEachWord(StringBuilder sb) {
            // 单词起始位置
            int start = 0;
            for (int end = 0; end <= sb.length(); end++) {
                // 遇到空格或字符串末尾时反转单词
                if (end == sb.length() || sb.charAt(end) == ' ') {
                    reverse(sb, start, end - 1);
                    // 更新下一个单词起始位置
                    start = end + 1; 
                }
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51

    # 首尾指针

    # 42. 接雨水 - 力扣(LeetCode) (opens new window)

    谁矮谁决定短板
    若 height[left] < height[right],说明左指针位置的柱子高度较低,此时​​左侧的最大高度 leftMax 是当前有效短板​​(因为右侧有更高的柱子 rightMax 挡水)。
    反之,若 height[left] >= height[right],则右侧是短板,由 rightMax 控制水位
    移动策略:谁矮移动谁
    当左指针较矮时(height[left] < height[right]),​​移动左指针​​(left++)。
    因为右侧已有更高的柱子(height[right] 较大),此时左侧的积水量仅由 leftMax 决定,与右侧更高柱子无关。
    反之,移动右指针(right--)
    
    1
    2
    3
    4
    5
    6
    7

    双指针

    class Solution {
        public int trap(int[] height) {
            int left = 0, right = height.length - 1;
            int leftMax = 0, rightMax = 0;
            int totalWater = 0;
            while (left < right) {
                 // 左侧更矮,左侧接水量可确定
                if (height[left] < height[right]) {
                    leftMax = Math.max(leftMax, height[left]);
                    totalWater += leftMax - height[left];
                    left ++;
                } else {
                    rightMax = Math.max(rightMax, height[right]);
                    totalWater += rightMax - height[right];
                    right --;
                }
            }
            return totalWater;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    单调栈

    //
    
    1

    # 前后双指针

    # 82. 删除排序链表中的重复元素 II - 力扣(LeetCode) (opens new window)

    class Solution {
        public ListNode deleteDuplicates(ListNode head) {
            if (head == null) return null;
               // 创建虚拟头节点,简化边界处理(如删除头节点)
            ListNode dummy = new ListNode(0);
            dummy.next = head;
            ListNode prev = dummy;
            ListNode cur = head;
            while (cur != null && cur.next != null) {
                // 检测重复值
                if (cur.val == cur.next.val) {
                    int duplicateVal = cur.val;
                    // 跳过所有重复节点
                    while (cur != null && cur.val == duplicateVal) {
                        cur = cur.next;
                    }
                    // 删除重复序列
                    prev.next = cur;
                } else {
                    // 无重复,移动prev保留当前节点
                    prev = cur;
                    cur = cur.next;
                }
            }
            return dummy.next;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    # 83. 删除排序链表中的重复元素 - 力扣(LeetCode) (opens new window)

    class Solution {
        public ListNode deleteDuplicates(ListNode head) {
            if (head == null) return null;
            ListNode cur = head;
            while (cur.next != null) {
                if (cur.val == cur.next.val) {
                    // 跳过重复节点
                    cur.next = cur.next.next;
                } else {
                    // 移动指针
                    cur = cur.next;
                }
            }
            return head;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    递归法

    class Solution {
        public ListNode deleteDuplicates(ListNode head) {
            if (head == null || head.next == null) return head;
            // 递归处理后续节点
            head.next = deleteDuplicates(head.next);
            // 去重逻辑
            return head.val == head.next.val ? head.next : head;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    # 24. 两两交换链表中的节点 - 力扣(LeetCode) (opens new window)

    class Solution {
        public ListNode swapPairs(ListNode head) {
            // 虚拟头节点
            ListNode dummy = new ListNode(0);
            dummy.next = head;
            ListNode cur = dummy;
    
            while (cur.next != null && cur.next.next != null) {
                ListNode node1 = cur.next;
                ListNode node2 = cur.next.next;
                ListNode node3 = node2.next;
                // 交换 node1 和 node2
                cur.next = node2;
                node2.next = node1;
                node1.next = node3;
                // 移动指针到下一组的前驱
                cur = node1;
            }
            return dummy.next;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    编辑 (opens new window)
    上次更新: 2025/07/25, 12:08:10
    递归
    滑动窗口

    ← 递归 滑动窗口→

    最近更新
    01
    加油鸭
    07-30
    02
    要点总结
    07-28
    03
    字符串
    07-15
    更多文章>
    Theme by Vdoing | Copyright © 2025-2025 plantre | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式