Double pointer method brushing questions
-
- remove element
- Remove duplicates in sorted array
- moving zero
- Compare strings with backspace*
- Square of sorted array
- reverse string
- replace spaces
- Reverse linked list: recursion + iteration + head insertion
- Delete the last Nth node of the linked list*
- Ring linked list: fast and slow pointer
- Ring Linked List II**
- linked list intersect*
- sum of three numbers**
- sum of four numbers
- Dividing line-----
- Longest substring without repeating characters*
remove element
Given an array nums
and a value val
, you need to remove all elements equal to the value in placeval
, and return the new length of the removed array.
Fast and slow pointer:
public int removeElement(int[] nums, int val) {
int l = 0;
for (int r = 0; r < nums.length; r++)
if (nums[r] != val) nums[l++] = nums[r];
return l;
}
Remove duplicates in sorted array
Given an array in ascending ordernums
, please delete repeated elements in place so that each element appears only once , and return the new length of the deleted array. The relative order of elements should be consistent .
Fast and slow pointer:
public int removeDuplicates(int[] nums) {
int l = 1;
for (int r = 1; r < nums.length; r++)
if (nums[r] != nums[l - 1]) nums[l++] = nums[r];
return l;
}
moving zero
Title: 283. Moving Zero - LeetCode
Given an array nums
, write a function to 0
move all to the end of the array while maintaining the relative order of the nonzero elements.
Fast and slow pointer:
class Solution {
public void moveZeroes(int[] nums) {
for (int l = 0, r = 0; r < nums.length; r++)
if (nums[r] != 0) swap(nums, l++, r);
}
void swap(int[] nums, int i, int j) {
nums[i] ^= nums[j];
nums[j] ^= nums[i];
nums[i] ^= nums[j];
}
}
Double pointer without swap:
public void moveZeroes(int[] nums) {
int l = 0;
// 将非 0 元素按顺序放到前面
for (int r = 0; r < nums.length; r++)
if (nums[r] != 0) nums[l++] = nums[r];
// 后面全部赋 0
while (l < nums.length) nums[l++] = 0;
}
Compare strings with backspace*
Given s
and t
two strings, when they are entered into a blank text editor, if they are equal, return true
. #
Represents the backspace character.
输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。
Restructure a string from front to back:
class Solution {
public boolean backspaceCompare(String s, String t) {
return getString(s).equals(getString(t));
}
public String getString(String s) {
StringBuilder sb = new StringBuilder();
char[] cs = s.toCharArray();
for (int i = 0; i < cs.length; i++) {
if (cs[i] != '#') sb.append(cs[i]);
else if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}
Restructure a string from back to front:
class Solution {
public boolean backspaceCompare(String s, String t) {
return getString(s).equals(getString(t));
}
private String getString(String s) {
StringBuilder sb = new StringBuilder();
char[] cs = s.toCharArray();
int size = 0; // '#' 数量
for (int i = cs.length - 1; i >= 0; i--) {
if (cs[i] == '#') size++;
else if (size == 0) sb.append(cs[i]);
else size--;
}
return sb.toString();
}
}
O(1) space complexity approach: hard. . .
Square of sorted array
Given an array of integers sorted in non-decreasing ordernums
, return a new array consisting of the square of each number , also sorted in non-decreasing order .
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
public int[] sortedSquares(int[] nums) {
int[] res = new int[nums.length];
int l = 0, r = nums.length - 1;
for (int i = nums.length - 1; i >= 0; i--) {
if (nums[l] + nums[r] < 0) {
// 左边绝对值大
res[i] = nums[l] * nums[l++];
} else {
// 右边绝对值大
res[i] = nums[r] * nums[r--];
}
}
return res;
}
reverse string
Write a function that reverses the input string. The input string s
is given as a character array.
Swap operations using bitwise operations:
public void reverseString(char[] s) {
int size = s.length - 1;
for (int i = 0; i < s.length / 2; i++) {
int j = size - i;
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
}
}
Generally, the inverted character array can be extracted into a template (this function is often used)
class Solution {
public void reverseString(char[] s) {
reverse(s, 0, s.length - 1);
}
// 反转字符数组
void reverse(char[] cs, int l, int r) {
while (l < r) {
cs[l] ^= cs[r];
cs[r] ^= cs[l];
cs[l++] ^= cs[r--];
}
}
}
replace spaces
Please implement a function to replace s
each space in the string with "%20".
Title: Sword Pointing to Offer 05. Replace spaces - LeetCode
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (c != ' ') sb.append(c);
else sb.append("%20");
}
return sb.toString();
}
Reverse linked list: recursion + iteration + head insertion
Given the head node of the singly linked list head
, please reverse the linked list and return the reversed linked list.
Double pointer:
public ListNode reverseList(ListNode head) {
ListNode cur = head, pre = null;
while (cur != null) {
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
recursion:
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode node = reverseList(head.next);
head.next.next = head;
head.next = null;
return node;
}
Head interpolation: space O(n)
public ListNode reverseList(ListNode head) {
ListNode res = null;
for (ListNode x = head; x != null; x = x.next)
res = new ListNode(x.val, res);
return res;
}
Delete the last Nth node of the linked list*
Topic: 19. Delete the last N node of the linked list - LeetCode
Given a linked list, delete the penultimate n
node of the linked list, and return the head node of the linked list.
Fast and slow pointer:
- The fast pointer moves n steps first, and then starts to move at the same time as the slow pointer
- When the fast pointer points to the last node, the slow pointer points to the node to be deleted (the previous node)
public ListNode removeNthFromEnd(ListNode head, int n) {
if (head == null || head.next == null) return null;
ListNode fast = head, slow = head;
while (n-- > 0) fast = fast.next; // 快指针先走 n 步
if (fast == null) return head.next; // 删除第一个节点
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}
Fast and slow pointer + virtual head node:
Generally using virtual head nodes does not need to deal with special cases
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode vn = new ListNode(0, head); // 虚拟头节点
ListNode slow = vn, fast = vn;
while (n-- > 0) fast = fast.next; // 快指针先走 n 步
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return vn.next;
}
recursion:
class Solution {
int cur = 0;
public ListNode removeNthFromEnd(ListNode head, int n) {
if (head == null) return null;
head.next = removeNthFromEnd(head.next, n);
cur++;
if (cur == n) return head.next;
return head;
}
}
Ring linked list: fast and slow pointer
Given the head node of a linked list head
, determine whether there is a ring in the linked list.
Fast and slow pointer:
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
hash:
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null && !set.contains(head)) {
set.add(head);
head = head.next;
}
return head != null;
}
Ring Linked List II**
Given the head node of a linked list head
, return the first node where the linked list starts entering the ring. Returns if the linked list is acyclic null
.
Fast and slow pointer judgment ring + find ring entry:
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
// 快慢指针判断是否有环
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
// 有环, 找环的起始点
fast = head; // 快指针从头开始
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
return null;
}
hash:
public ListNode detectCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null && !set.contains(head)) {
set.add(head);
head = head.next;
}
return head;
}
linked list intersect*
Topic: Interview Question 02.07. Linked List Intersection - LeetCode
Given the sum of the head nodes of two singly linked lists headA
, headB
please find and return the starting node where the two singly linked lists intersect. If there is no intersection between the two linked lists, return null
.
Double pointer:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA, curB = headB;
int lenA = 0, lenB = 0;
// 求链表 A 的长度
while (curA != null) {
lenA++;
curA = curA.next;
}
// 求链表 B 的长度
while (curB != null) {
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
// 链表 A 更长则让 A 多走, B 更长则让 B 多走,保证 A B 从同一位置开始比较
if (lenA > lenB) for (int i = 0; i < lenA - lenB; i++) curA = curA.next;
else for (int i = 0; i < lenB - lenA; i++) curB = curB.next;
// 逐个比较 A 和 B
while (curA != null) {
if (curA == curB) return curA;
curA = curA.next;
curB = curB.next;
}
return curA;
}
Clever approach:
- a goes to b, b goes to a, if there is an intersection point, it will inevitably meet
- If there is no intersection point, it will end up meeting at
null
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode h1 = headA, h2 = headB;
while (h1 != h2) {
h1 = (h1 == null) ? headB : h1.next;
h2 = (h2 == null) ? headA : h2.next;
}
return h1;
}
hash:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> set = new HashSet<>();
ListNode p = headA;
while (p != null) {
set.add(p);
p = p.next;
}
p = headB;
while (p != null) {
if (set.contains(p)) return p;
p = p.next;
}
return null;
}
sum of three numbers**
Given an array of integers nums
, determine whether there is a triple [nums[i], nums[j], nums[k]]
that satisfies i != j
, i != k
and j != k
, and satisfies at the same time nums[i] + nums[j] + nums[k] == 0
. Please return all 0
triples whose sum is and are not repeated.
**Note:** The answer cannot contain repeated triplets.
Ideas:
- sort array
- Define i, j, k three pointers. Traversing i, transforming the problem into finding in the array after i
nums[j] = nums[k] = -nusm[i]
- Pay attention to find while going to heavy
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
Arrays.sort(nums);
// 剪枝: 最小的数 > 0 或 最大的数 < 0, 不可能和为 0
if (nums[0] > 0 || nums[n - 1] < 0) return res;
// 转化成两数之和: 寻找 nums[j] + nums[k] = -nums[i]
for (int i = 0; i < n; i++) {
if (nums[i] > 0) break; // 不可能找到和为 0 的三元组
if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
// 两数之和寻找方法: 双指针, j 从前开始, k 从后开始
int j = i + 1, k = n - 1, target = -nums[i];
while (j < k) {
if (nums[j] + nums[k] < target) j++;
else if (nums[j] + nums[k] > target) k--;
else {
res.add(Arrays.asList(nums[i], nums[j], nums[k]));
while (j < k && nums[j] == nums[j + 1]) j++; // 去重
while (j < k && nums[k] == nums[k - 1]) k--; // 去重
j++;
k--;
}
}
}
return res;
}
sum of four numbers
You are given an n
array of integers nums
, and a target value target
. Please find and return the quadruples that meet all the following conditions and are not repeated [nums[a], nums[b], nums[c], nums[d]]
(if the two quadruple elements correspond to each other, the two quadruples are considered to be repeated):
0 <= a, b, c, d < n
a
,b
,c
andd
are different from each othernums[a] + nums[b] + nums[c] + nums[d] == target
You can return answers in any order .
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
if (n < 4) return res;
Arrays.sort(nums);
// 处理越界的情况: 正 + 正 = 负
if (nums[0] > 0 && target <= 0 || nums[n - 1] < 0 && target >= 0) return res;
for (int i = 0; i < n - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
// 剪枝: 当前情况的最小和 > target 或 最大和 < target
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
if ((long) nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) continue;
for (int j = i + 1; j < n - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue; // 去重
// 剪枝: 当前情况的最小和 > target 或 最大和 < target
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
if ((long) nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) continue;
// 两数之和
int k = j + 1, l = n - 1;
while (k < l) {
int sum = nums[i] + nums[j] + nums[k] + nums[l];
if (sum < target) k++;
else if (sum > target) l--;
else {
res.add(Arrays.asList(nums[i], nums[j], nums[k], nums[l]));
while (k < l && nums[k] == nums[k + 1]) k++; // 去重
while (k < l && nums[l] == nums[l - 1]) l--; // 去重
k++;
l--;
}
}
}
}
return res;
}
Dividing line-----
Longest substring without repeating characters*
Topic: 3. The longest substring without repeating characters - LeetCode
Given a string s
, find the length of the longest substring that does not contain repeated characters .
Double pointer:
public int lengthOfLongestSubstring(String s) {
char[] cs = s.toCharArray();
int[] map = new int[128]; // 字符 与 出现次数
int res = 0;
for (int l = 0, r = 0; r < cs.length; r++) {
map[cs[r]]++; // 访问字符
while (map[cs[r]] > 1) map[cs[l++]]--;
res = Math.max(res, r - l + 1);
}
return res;
}