141.环形链表
不能对节点的值做字典映射,因为可能有相同的值。
1、Hash
- Python实现
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
dic = {}
while head != None:
if head not in dic:
dic[head] = 1
else:
return True
head = head.next
return False
执行用时: 40 ms
内存消耗: 20.9 MB
- Java实现
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> seen = new HashSet<ListNode>();
while (head != null){
if (!seen.add(head)){
return true;
}else {
head = head.next;
}
}
return false;
}
}
执行用时:4 ms, 在所有 Java 提交中击败了20.73%的用户
内存消耗:38.7 MB, 在所有 Java 提交中击败了98.83%的用户
新知识
//新数据类型:哈希集合,集合,尖括号内表示集合元素的类型
Set<...> seen = new HashSet<...>();//多态;需要括号
//如果添加的元素集合中已经存在,则返回false
seen.add(head)
2、双指针
龟兔赛跑算法:开始乌龟在兔子后面,乌龟每次爬一步,兔子每回跑两步,如果链表中有环,则乌龟会与兔子相遇。
空间复杂度:O(1)
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
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;
}
}
160.相交链表
1、哈希
/**
* 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) {
//HashSet 两次遍历
Set<ListNode> seen = new HashSet<ListNode>();
ListNode temp = headA;
while (temp != null){
seen.add(temp);
temp = temp.next;
}
temp = headB;
while (temp != null){
if (!seen.add(temp)){
return temp;
}
temp = temp.next;
}
return null;
}
}
执行用时:9 ms, 在所有 Java 提交中击败了8.02%的用户
内存消耗:41.7 MB, 在所有 Java 提交中击败了18.13%的用户
2、双指针
和龟兔赛跑算法类似,A表完了从B头开始,B表完了从A头开始,总会有相遇的时候。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null){
return null;
}
ListNode pA = headA, pB = headB;
while (pA != pB){
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
执行用时:1 ms, 在所有 Java 提交中击败了99.99%的用户
内存消耗:40.9 MB, 在所有 Java 提交中击败了91.87%的用户
203.移除链表
1. 迭代
/**
* 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 removeElements(ListNode head, int val) {
//当链表为空时,直接返回
if (head == null){
return head;
}
//因为表头可能也要删除,因此创建哑巴节点
ListNode prehead = new ListNode(-1);
prehead.next = head;
ListNode cur = prehead;
while (cur.next != null){
if (cur.next.val == val){
cur.next = cur.next.next;
}else {
cur = cur.next;
}
}
return prehead.next;
}
}
执行用时:1 ms, 在所有 Java 提交中击败了96.30%的用户
内存消耗:38.8 MB, 在所有 Java 提交中击败了97.70%的用户
2. 递归
链表的定义具有递归的性质
class Solution {
public ListNode removeElements(ListNode head, int val) {
if (head == null) {
return head;
}
head.next = removeElements(head.next, val);
return head.val == val ? head.next : head;
}
}