合并有序链表
// 21
public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
// 3. 递归跳出条件
if(list1 == null){
return list2;
}
if(list2 == null){
return list1;
}
// 1. 比较大小,值小的放入res
ListNode res = list1.val < list2.val?list1:list2;
// 2. 进行递归,res的下一个与list1、list2值较大的进行比较
// list1、list2来回切换逐一比较各自的值
res.next = mergeTwoLists2(res.next,list1.val >= list2.val?list1:list2);
return res;
}
删除链表中重复的元素
思路:记录上一个节点的元素,用来后续的比较,如果不相等,当前节点成为上一个节点
已经排过序的,逐一扫描,没有排序的可以借助存储(重点在重复上),如map、set等
// 83
public ListNode deleteDuplicates(ListNode head) {
if(head == null){
return null;
}
ListNode pre = head;
ListNode cur = head.next;
while(cur != null){
if(cur.val == pre.val){
pre.next = cur.next;
}else{
pre = cur;
}
cur = cur.next;
}
return head;
}
// 203
public ListNode removeElements(ListNode head, int val) {
ListNode res = head;
ListNode pre = head;
while(head != null){
if(head.val == val){
pre.next = head.next;
}else{
pre = head;
}
head = head.next;
}
if(res != null && res.val == val){
res = res.next;
}
return res;
}
// 面试题 02.01. 移除重复节点
public ListNode removeDuplicateNodes(ListNode head) {
Map map = new HashMap();
ListNode pre = head;
ListNode cur = head;
while(cur != null){
if(!map.containsKey(cur.val)){
map.put(cur.val,cur);
pre = cur;
}else{
pre.next = cur.next;
}
cur = cur.next;
}
return head;
}
删除链表中的节点
思路:链表中的节点和值是两回事
// 237. 删除链表中的节点
// 将儿子的值给了它,然后它的孙子变成它的儿子
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
链表的中间节点(快慢指针)
思路:快慢指针,快指针走完的时候,慢指针正好走到中间
// 876. 链表的中间结点
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
int k = 0;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
k++;
}
return slow;
}
查找倒数第k个结点
思路:
带头结点的单链表,结点结构为(data,next),在不改变链表的前提下,设计一个尽可能高效的算法,查找出链表中倒数第k(k为正整数)个位置上的结点。
第一种方法是先循环一遍链表确定结点个数n,则倒数第k个结点就是就是正数的第n+1-k个,然后在遍历一次链表就可以找到指定结点了,但显然需要遍历两遍链表。
第二种方法可以使用两个指针,第一个指针先走k-1步,然后第二个指针开始走。当第一个指针移动到最后时,第二个指针正好指向倒数第k个结点,只需要遍历一遍链表,显然更高效。