链表操作一般小trike:设置一个空的节点指向头,以防止后续出现null的问题
21. 合并两个有序链表
解法:
双指针,一个指针指向A,一个指针指向B,比较两指针哪个val小,就先让新链表的头指向该指针的值
代码:
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1==null && list2==null){ // 都为空,则返回null
return null;
}
if(list1==null){ // 其中一个为空,则返回另一个
return list2;
}
if(list2==null){
return list1;
}
ListNode dummyNode = new ListNode(0);
ListNode d = dummyNode;
ListNode l1 = list1;
ListNode l2 = list2;
while(l1!=null && l2!=null){
if(l1.val<=l2.val){
d.next = l1;
l1 = l1.next;
}else{
d.next = l2;
l2 = l2.next;
}
d = d.next;
}
if(l1!=null){ // 如果还有某个链表未遍历完,直接把后面的链到新链表即可
d.next = l1;
}
if(l2!=null){
d.next = l2;
}
return dummyNode.next;
}
}
23. 合并K个升序链表
解法:
这就需要不断找出k个链表中的最小值了。怎么找?优先级队列。这是一个很好的东西,可以自定义比较器,选择队列中元素作比较
代码:
class Solution {
// 不断找出k个链表中的最小值,这就需要用到优先级队列
// 优先级队列,可分为大堆和小堆,new的时候可以自定义比较器,来选择所有元素的max还是min
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) { // 空集合
return null;
}
ListNode dummyNode = new ListNode(-1);
ListNode d = dummyNode;
// 新建一个优先级队列,数值越小的Node,越先被选择
PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
});
// 把所有链表的头结点加入队列中
for (ListNode head : lists) {
if (head != null) {
queue.offer(head);
}
}
// 遍历队列,每次取出队头元素即为最小值
while (!queue.isEmpty()) {
ListNode top = queue.poll(); // 出队头
d.next = top;
if (top.next != null) { // 如果该结点仍有后续结点,直接入队
queue.offer(top.next);
}
d = d.next;
}
return dummyNode.next;
}
}
876. 链表的中间结点
图解:
代码:
class Solution {
// 快慢双指针
public ListNode middleNode(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast!=null && fast.next!= null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
19. 删除链表的倒数第 N 个结点
解法一:
删除倒数第N个节点,即删除正数第len-N+1个节点,因为不知道链表长度len,所以需要第一次遍历,得到节点个数len;第二次遍历找到第len-N+1个结点
代码:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int len = getLength(head);
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode d = dummyNode;
// 找到正数第m个节点的前一个节点
for(int i=1;i<(len-n+1);i++){
d = d.next;
}
// 让前一个节点执行m的后一个节点即删除第m个节点
d.next = d.next.next;
return dummyNode.next;// 返回头结点
}
public int getLength(ListNode head){
int count = 0;
while(head!=null){
count++;
head = head.next;
}
return count;
}
}
解法二:
双指针,一次遍历即可:指针p1指向head,向前走n步,那么剩下的就是len-N步了,而我们正需要删除正数第len-N+1个节点,此时让p2指向head,p1和p2同时后移,直至p1.next为null,此时p2刚好指向正数第len-N+1个结点的前一个结点。
代码:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode p1 = dummyNode;
int i = 0;
while (i < n) { // p1走n步,剩下的结点个数刚好是len-n个
p1 = p1.next;
i++;
}
ListNode p2 = dummyNode;
while (p1.next != null) { // 若p1.next=null,那么我们已经找到了将被删除的节点的前一个几点
p1 = p1.next;
p2 = p2.next;
}
p2.next = p2.next.next;
return dummyNode.next;
}
}
141. 环形链表
解法:
快慢双指针,相遇即是有环
代码:
public class Solution {
// 判断链表是否有环,快慢指针,快满指针相遇,即有环
public boolean hasCycle(ListNode head) {
if(head==null || head.next==null){ // 特殊情况
return false;
}
ListNode fast = head;
ListNode slow = head;
while(fast!=null && fast.next!=null){
fast = fast.next.next; // 先移动,再比较
slow = slow.next;
if(fast==slow){ // 说明无环
return true;
}
}
return false;
}
}
142. 环形链表 II
解法:
快慢双指针,相遇即是有环,若有环,让快慢其中一个指针和新的指针(指向head)同步长移动,相遇即是入环的第一个节点
代码:
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null){ // // 空链,必无环
return null;
}
ListNode fast = head;
ListNode slow = head;
ListNode p = head;
while(fast != null && fast.next != null){ // 但凡其中一个为null,则表示没有环
fast = fast.next.next;
slow = slow.next;
if(fast == slow){ // 相遇表示有环
while(slow != p){ // 新的指针指向head,和slow同步长移动,相遇即是入环结点
slow = slow.next;
p = p.next;
}
return p;
}
}
return null;
}
}
160. 相交链表
解法:
p1指向A,p2指向B,同步往前走,如果p1==null,p1指向B;如果p2==null,p2指向A,p1和p2相遇,即交点、
代码:
public class Solution {
// p1指向A,p2指向B,一直往前走,如果p1==null,p1指向B,如果p2==null,p2指向A,直至p1和p2相遇,即交点
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA;
ListNode p2 = headB;
while(p1!=p2){ // 相遇即交点
if(p1==null){
p1 = headB;
}else{
p1 = p1.next;
}
if(p2==null){
p2 = headA;
}else{
p2 = p2.next;
}
}
return p1;
}
}