算法-链表
1. 移除链表元素(LeetCode 233)
题目:删除链表中等于给定值 val 的所有节点。
示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
示例 2: 输入:head = [], val = 1 输出:[]
示例 3: 输入:head = [7,7,7,7], val = 7 输出:[]
思路:
- 设置虚拟节点:这样对头节点和后面节点的处理是一致的(都有前驱节点)
- C++/C需要对删除的节点进行内存释放;java不需要程序员手动操作,内存机制会自动释放。
/**
* 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) {
// 在原来的链表前面设置一个虚拟头节点
ListNode newhead = new ListNode(0,head);
ListNode pre = newhead;
ListNode current = newhead.next;
while(current != null){
if(current.val == val) {
pre.next = current.next;
}else {
pre = current;
}
current = current.next;
}
return newhead.next;
}
}
2. 设计链表(LeetCode 707)
题目:详见LeetCode
注意:
- 注意index的边界条件判断
- 这里的index定义和数组相同,是从0开始的
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 MyLinkedList {
ListNode dummy_head; //虚拟头节点
int size;
public MyLinkedList() {
this.dummy_head = new ListNode(0,null);
this.size = 0;
}
public int get(int index) {
int count = 0;
if(index < 0 || index >= this.size ) return -1;
ListNode cur = dummy_head.next;
while(count < index){
count++;
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
ListNode newnode = new ListNode(val,dummy_head.next);
this.dummy_head.next = newnode;
this.size++;
}
public void addAtTail(int val) {
ListNode newnode = new ListNode(val,null);
ListNode cur = this.dummy_head.next;
if(this.size == 0){
dummy_head.next = newnode;
this.size++;
return;
}
while(cur.next != null){
cur = cur.next;
}
cur.next = newnode;
this.size++;
return;
}
public void addAtIndex(int index, int val) {
if(index > this.size) return;
else if(index <= 0){
addAtHead(val);
return;
}else if(index == this.size){
addAtTail(val);
return;
}
int count = 0;
ListNode cur = this.dummy_head.next;
while(count < index-1) {
cur = cur.next;
count++;
}
ListNode newNode = new ListNode(val, cur.next);
cur.next = newNode;
this.size++;
}
public void deleteAtIndex(int index) {
if(index < 0 || index >= this.size) return;
int count = -1;
ListNode pre = this.dummy_head;
while(count < index-1){
pre = pre.next;
count++;
}
pre.next = pre.next.next;
this.size--;
}
}
3. 反转链表(LeetCode 206)
题目:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
思路:
- 双指针
- 需要存储cur.next否则会找不到后面的节点。
//双指针pre and cur
//用tmp存储cur.next
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode pre = null;
ListNode tmp;
while(cur != null) {
tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
4. 两两交换链表中的节点
题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
注意:操作的顺序,不要丢失指针导致链表断裂
输入:head = [1,2,3,4]
输出:[2,1,4,3]
//两两配对,进行交换
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy_head = new ListNode(-1, head);
ListNode cur = dummy_head;
ListNode tmp = null;
while(cur!=null && cur.next != null && cur.next.next != null){
tmp = cur.next;
cur.next = cur.next.next;
tmp.next = cur.next.next;
cur.next.next = tmp;
cur = cur.next.next;
}
return dummy_head.next;
}
}
5. 删除链表的倒数第N个节点(LeetCode 19)
题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
思路:简单的快慢指针,注意处理第一个节点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode slow = head;
ListNode fast = head;
ListNode pre = slow;
int count = n;
while(fast != null && count > 0){
fast = fast.next;
count--;
}
//要删除的是第一个节点
if(fast == null){
head = head.next;
}
//要删除的不是第一个节点
while(fast != null){
pre = slow;
slow = slow.next;
fast = fast.next;
}
pre.next = slow.next;
return head;
}
}
6. 链表相交
题目:见LeetCode
思路:
- 确定链表长度
- 尾部对齐(长的指针先走len_long-len_short步)
- 查找相同的节点(值相同,next相同)
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = 0;
int lenB = 0;
ListNode temp = headA;
while(temp != null){
lenA++;
temp = temp.next;
}
temp = headB;
while(temp != null){
lenB++;
temp = temp.next;
}
ListNode long_list = (lenA >= lenB) ? headA : headB;
ListNode short_list = (lenA < lenB) ? headA : headB;
int gap = Math.abs(lenA-lenB);
while(gap != 0){
long_list = long_list.next;
gap--;
}
while(long_list!=null){
//节点相等,而不仅仅是值相等
if(long_list == short_list) return long_list;
long_list = long_list.next;
short_list = short_list.next;
}
return null;
}
}
7. 环形链表II(LeetCode 142)
题目:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
//退出循环的条件: 无环 或 fast、slow相遇
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow) break;
}
//无环返回null
if(fast == null || fast.next == null) return null;
//有环则令两个指针分别从 head 和 相遇点 出发
//两者相等的节点即为环的起点
ListNode index1 = head;
ListNode index2 = fast;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}