👨💻个人主页: 才疏学浅的木子
🙇♂️ 本人也在学习阶段如若发现问题,请告知非常感谢 🙇♂️
📒 本文来自专栏: 算法
🌈 算法类型:Hot100题 🌈
❤️ 支持我:👍点赞 🌹收藏 🤟关注
环形链表I
解法一
哈希集合
遍历链表并判断哈希集合里面是否包含当前节点
如果包含则存在环
public class Solution {
public boolean hasCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<>();
while(head != null){
if(set.contains(head)) return true;
else set.add(head);
head = head.next;
}
return false;
}
}
解法二
双指针
一个quick指针一个slow指针
quick每次走两步
slow每次走一步
假如没有环
那么quick就会为空,直接返回false
如果有环
那么quick回比slow先进入环,slow后进入环
他们总会在环里相遇所有quick == slow
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null) return false;
ListNode quick = head.next;
ListNode slow = head;
while(quick != slow){ // 不相等就一直循环
if(quick == null || quick.next == null) return false; // 如果为空直接退出
quick = quick.next.next;
slow = slow.next;
}
return true;
}
}
环形链表II
解法一
哈希集合
如果在该哈希集合中存在就返回当前节点
public class Solution {
public ListNode detectCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<>();
while(head != null){
if(set.contains(head)) return head;
else set.add(head);
head = head.next;
}
return null;
}
}
解法二
双指针
像环形链表1一样可以找到相遇节点
然后slow指向头节点,然后quick与slow每次向后移动一步直到相遇
所以下次相遇时候就是第一个节点
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head == null)return head;
ListNode quick = head;
ListNode slow = head;
while(true){
if(quick == null || quick.next == null) return null;
quick = quick.next.next;
slow = slow.next;
if(quick == slow) break;
}
slow = head;
while(quick != slow){
slow = slow.next;
quick = quick.next;
}
return quick;
}
}
注意!!!
如果相遇那个方法是第一种的话,即quick = head.next
那么quick需要在相遇之后再向移动一个位置,推到如上
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head == null)return head;
ListNode quick = head.next;
ListNode slow = head;
while(quick != slow){
if(quick == null || quick.next == null) return null;
quick = quick.next.next;
slow = slow.next;
}
slow = head;
quick = quick.next;
while(quick != slow){
slow = slow.next;
quick = quick.next;
}
return quick;
}
}
排序链表
解法一
使用优先队列
先循环一遍把当前节点放进去,再重构有序链表
class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null) return head;
PriorityQueue<ListNode> p = new PriorityQueue<>((l1,l2)->l1.val-l2.val);
ListNode t = head;
while(t != null){ // 遍历进优先队列
p.add(t);
t = t.next;
}
ListNode res = new ListNode();
t = res;
while(!p.isEmpty()){ // 重构
ListNode node = p.poll();
t.next = node;
t = t.next;
}
t.next = null; // 避免出现环
return res.next;
}
}
解法二
归并排序
从顶到底
class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null) return head;
ListNode quick = head.next;
ListNode slow = head;
while(quick != null && quick.next != null){
quick = quick.next.next;
slow = slow.next;
}
ListNode mid = slow.next;
slow.next = null; // 将一个链表断开为两个链表
ListNode left = sortList(head);
ListNode right = sortList(mid);
// 相当于两个有序链表的合并
ListNode res = new ListNode();
ListNode t = res;
while(left != null && right != null){
if(left.val < right.val){
t.next = left;
left = left.next;
}else{
t.next = right;
right = right.next;
}
t =t.next;
}
if(left != null) t.next = left;
if(right != null) t.next = right;
return res.next;
}
}