双指针(逆向,快慢)
# 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
2
3
4
5
6
7
8
9
10
11
12
13
14
覆盖+补零法:
- 快指针覆盖慢指针:将非零元素直接前移。
- 末尾补零:遍历结束后将慢指针后的位置置零
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
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
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
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
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
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
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
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
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
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
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
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