面试过程中,总是被拷打,信心都要没了。但是也慢慢摸索出一些思路,希望对大家有帮助。
(需要多用一下ACM模式,力扣模式提供好了模板,自己在IDEA里面写的话,还是会有些陌生)
0、基本Java类型
1、用双指针思路去解决链表问题
定义一个单链表
class ListNode{
int val;
ListNode next;
ListNode(int x){
val = x;
next = null;
}
}
力扣21 - 合并两个有序链表
/**
public class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val; this.next = next;
}
}
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
//虚拟头结点
ListNode dummy = new ListNode(-1), p = dummy;
ListNode p1 = list1 ,p2 = list2;
while(p1 != null && p2 != null){
//比较p1和p2两个指针,把值较小的节点接到p指针
if( p1.val > p2.val){
p.next = p2;
p2 = p2.next;
}else{
p.next = p1;
p1 = p1.next;
}
p = p.next;
}
if(p1 != null){
p.next = p1;
}
if(p2 != null){
p.next = p2;
}
return dummy.next;
}
}
力扣19 - 删除倒数第k个节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode x = findFromEnd(dummy, n+1);
x.next = x.next.next;
return dummy.next;
}
private ListNode findFromEnd(ListNode head, int k) {
ListNode p1 = head;
for (int i = 0; i< k; i++){
p1 = p1.next;
}
ListNode p2 = head;
while( p1 != null){
p2 = p2.next;
p1 = p1.next;
}
return p2;
}
}
这段代码的目的是从单向链表中移除倒数第 n
个节点。为了实现这一点,代码使用了一个辅助的虚拟头节点(dummy node)和双指针方法。以下是详细的解释:
链表节点类的定义
首先是链表节点的定义,类名为 ListNode
:
public class ListNode {
int val;
ListNode next; ListNode() {} ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
removeNthFromEnd
方法的解释
这是移除倒数第 n
个节点的方法:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(-1);
dummy.next = head;ListNode x = findFromEnd(dummy, n + 1);
x.next = x.next.next;
return dummy.next;
}private ListNode findFromEnd(ListNode head, int k) {
ListNode p1 = head;for (int i = 0; i < k; i++) {
p1 = p1.next;
}ListNode p2 = head;
while (p1 != null) {
p2 = p2.next;
p1 = p1.next;
}return p2;
}
}
具体思路
1. 使用虚拟头节点
ListNode dummy = new ListNode(-1); dummy.next = head;
2. 找到倒数第 n+1
个节点
ListNode x = findFromEnd(dummy, n + 1);
调用 findFromEnd
方法,找到倒数第 n+1
个节点。之所以要找到倒数第 n+1
个节点,是为了方便我们进行节点删除操作,因为我们需要操作的是前一个节点的 next
指针。
3. 删除节点
x.next = x.next.next;
将倒数第 n+1
个节点的 next
指针指向其下下个节点,从而删除倒数第 n
个节点。
4. 返回结果
return dummy.next;
返回虚拟头节点的 next
指针,即新的链表头。
findFromEnd
方法的解释
这个方法的目的是找到从链表末尾数起的第 k
个节点。
private ListNode findFromEnd(ListNode head, int k) { ListNode p1 = head; for (int i = 0; i < k; i++) { p1 = p1.next; } ListNode p2 = head; while (p1 != null) { p2 = p2.next; p1 = p1.next; } return p2; }
1. 初始化指针
ListNode p1 = head;
首先初始化指针 p1
指向链表头节点。
2. 移动 p1
指针
for (int i = 0; i < k; i++) { p1 = p1.next; }
将 p1
指针向前移动 k
步。
3. 初始化 p2
指针
ListNode p2 = head;
初始化另一个指针 p2
指向链表头节点。
4. 同步移动 p1
和 p2
指针
while (p1 != null) {
p2 = p2.next;
p1 = p1.next;
}
同步移动 p1
和 p2
指针,直到 p1
到达链表末尾。此时 p2
指向的就是从末尾数起的第 k
个节点。
5. 返回 p2
指针
return p2;
返回 p2
指针,即倒数第 k
个节点。
总结
这段代码通过创建一个虚拟头节点,并使用双指针方法来找到并删除倒数第 n
个节点。反复利用 findFromEnd
方法来找到关键节点,并调整链表指针以删除目标节点。这种方法有效地解决了移除链表倒数第 n
个节点的问题,同时简化了边界条件的处理。
力扣876 - 链表的中间结点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
力扣142 - 环形链表
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;
}
// 上面的代码类似 hasCycle 函数
if (fast == null || fast.next == null) {
// fast 遇到空指针说明没有环
return null;
}// 重新指向头结点
slow = head;
// 快慢指针同步前进,相交点就是环起点
while (slow != fast) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
160 - 相交链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA, p2 = headB;
while(p1 != p2){
if(p1 == null) p1 = headB;
else p1 = p1.next;
if(p2 ==null) p2 = headA;
else p2 = p2.next;
}
return p2;
}
}
2、双指针解决数组问题
class Solution {
public int removeDuplicates(int[] nums) {
int slow = 0, fast = 0;
while(fast < nums.length){
if(nums[slow] != nums[fast]){
slow++;
nums[slow] = nums[fast];
}
fast++;
}
return slow+1;
}
}
class Solution {
public int removeElement(int[] nums, int val) {
int readIndex = 0;
int writeIndex = 0;
while(readIndex < nums.length){
if(nums[readIndex] != val){
nums[writeIndex] = nums[readIndex];
writeIndex++;
}
readIndex++;
}
return writeIndex;
}
}
未完待续。。。。