1 反转链表
题目:https://leetcode-cn.com/problems/reverse-linked-list/
思路:把每个链表next 指向前驱节点即可,类似链表头插入法
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null) {
return head;
}
//前一个节点,一开始为空
ListNode prev=null;
//当前节点
ListNode cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=prev;
//节点后移
prev=cur;
cur=next;
}
return prev;
}
}
反转链表指定位置:https://leetcode-cn.com/problems/reverse-linked-list-ii/
思路:找到要反转的部分,对该部分进行反转,要保留前驱和后继节点。
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
//几种场景不用处理
if (head == null || head.next == null || right == left) {
return head;
}
ListNode vHead = new ListNode(-1);
vHead.next = head;
ListNode cur = vHead;
ListNode startPre = null, end = null, start = null;
int count = 0;
while (cur != null) {
count++;
//找到要反转开始前驱,由于加了一个虚拟头
if (left == count) {
startPre = cur;
}
// 找到要反转的结尾
if (count == right + 1) {
end = cur;
//记录end next 节点
cur = cur.next;
end.next = null;
break;
}
cur = cur.next;
}
start = startPre.next;
startPre.next = reverse(start);
if (start != null) {
//end next 节点为开始节点反转后的后继节点
start.next = cur;
}
return vHead.next;
}
private ListNode reverse(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode cur = head, prev = null;
while (cur != null) {
ListNode next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
}
2 两两交换链表
题目:https://leetcode-cn.com/problems/swap-nodes-in-pairs/
思路:用两个指针分别移动,要考虑到边界问题
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode slow = head, fast = head.next;
ListNode newHead = head.next;
while (fast != null && slow != null) {
ListNode next = fast.next;
fast.next = slow;
slow.next = next;
//判断接下来有没有两个,如果有两个,要连接到反转后的
if (next != null && next.next != null) {
slow.next = next.next;
}
//后移
slow = next;
if (slow != null) {
fast = slow.next;
}
}
return newHead;
}
3 判断链表有没有环
题目:https://leetcode-cn.com/problems/linked-list-cycle/
思路1:有环说明会访问重复节点记录,使用set 记录访问过的节点,如果节点有重复说明有环存在
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
Set<ListNode> set = new HashSet<>();
ListNode p = head;
while (p != null) {
if (set.contains(p)) {
return true;
}
set.add(p);
p = p.next;
}
return false;
}
}
思路2:快慢指针法,快指针比慢指针多走一步,如果有环的的话,快慢指针一定能相遇(在环里可能转了几个圈)
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null||head.next==null){
return false;
}
ListNode slow=head,fast=head.next;
while(slow!=fast){
if(fast==null || fast.next==null) {
return false;
}
fast=fast.next.next;
slow=slow.next;
}
return true;
}
}
题目:https://leetcode-cn.com/problems/linked-list-cycle-ii/
思路1:使用set记录访问过的节点,如果第一次找到重复的地方,就说明有环的节点头。
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
Set<ListNode> set = new HashSet<>();
ListNode cur = head;
while (cur != null) {
if (set.contains(cur)) {
return cur;
} else {
set.add(cur);
}
cur = cur.next;
}
return null;
}
}
思路1:快慢指针法,待补充
4 总结
链表思考要动手画下图,引入虚拟节点,可以适当简化代码。