刷题之旅211004

数据结构

单链表

1、合并2个有序链表(lc21)

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 mergeTwoLists(ListNode l1, ListNode l2) {
        //虚拟头指针
        ListNode dump = new ListNode(-1), p = dump;
        ListNode p1 = l1, p2 = l2;

        while(p1!=null && p2!=null){
            if(p1.val <= p2.val){
                p.next = p1;
                p1 = p1.next;
            }
            else{
                p.next = p2;
                p2 = p2.next;
            }
            p = p.next;
        }
        if(p1 != null)
            p.next = p1;
        if(p2 != null)
            p.next = p2;
        return dump.next;
    }
}
python

2、合并K个有序链表(lc23)

分析

1、如何快速找到k个节点中最小节点:优先级队列(二叉堆)(最小堆)
2、算法时间复杂度:优先队列小根堆排序时间为logk,故总时间Nlogk

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 mergeKLists(ListNode[] lists) {
        if(lists.length == 0) return null;
        //虚拟头结点
        ListNode dump = new ListNode(-1), p = dump;
        //优先级队列,最小堆
        PriorityQueue<ListNode> pq = new PriorityQueue<>(lists.length, (a, b)->(a.val-b.val));
        //将k个链表头结点加入小根堆
        for(ListNode head : lists){
            if(head != null)
                pq.add(head);
        }

        while(!pq.isEmpty()){
            //获取最小节点存入结果链表中
            ListNode node = pq.poll();
            p.next = node;
            if(node.next != null)
                pq.add(node.next);
            p = p.next;
        }

        return dump.next;
    }
}

3、单链表倒数第k个节点(lc19)

分析

1、2个节点 一个先走k步,后面2个节点一起走n-k步

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 removeNthFromEnd(ListNode head, int n) {
        // ListNode p1 = head;
        // ListNode p2 = findFromEnd(head, n+1);
        // p2.next = p2.next.next;
        ListNode dump = new ListNode(-1);
        dump.next = head;
        ListNode x = findFromEnd(dump, n+1);
        x.next = x.next.next;
        return dump.next;
    }

    private ListNode findFromEnd(ListNode head, int k){
        ListNode p1 = head;
        //p1先走k步
        for(int i=0; i<k; i++){
            p1 = p1.next;
            // System.out.print(p1.val);
        }
        ListNode p2 = head;
        //p1 p2一起走n-k步
        while(p1 != null){
            p2 = p2.next;
            p1 = p1.next;
        }
        //p2指向倒数第n-k个节点
        return p2;
    }
}

4、单链表的中间节点(lc876)

分析

1、快慢步骤 一个走1步,一个走2步

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 middleNode(ListNode head) {
        ListNode slow=head, fast=head;

        while(fast!=null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }

        return slow;
    }
}

5、判断链表是否有环

分析

1、使用快慢指针,如果fast=slow 证明有环,fast已经比slow多走一环了

java
boolean hasCycle(ListNode head){
	ListNode fast=head, slow=head;
	while(fast!=null && fast.next!=null){
		slow = slow.next;
		fast = fast.next.next;
		if(fast == slow)
			return true;
	}
	return false;
}
升级:判断环的起点
分析

1、slow 走了K步, fast走了2K步;设相遇点 距离 环起点为 M步
那么slow 再从头开始走k-m步; fast 从 相遇点也走k-m步, 最终他们将在环起点相遇。

java
public ListNode detectCycle(ListNode head){
	ListNode slow=head, fast=head;
	while(fast!=null && fast.next!=null){
		slow = slow.next;
		fast = fast.next.next;
		if(slow == fast)
			break;
	}
	if(fast == null || fast.next = null)
		return null;//遇到空指针 说明没有环
	//重新指向头结点
	slow = head;
	while(slow != fast){
		slow = slow.next;
		fast = fast.next;
	}
	return slow;
}

6、两个链表是否相交(lc160)

分析

1、将两个链表分别拼接 ,然后依次从头访问 若遇到相同节点时,则停止,存在相交。如:
p1: a s d f g
p2: x d f g
p1+p2: a s d f g x d f g
p2+p1: x d f g a s d f g
显然倒数第三个d开始是相交的

java
public ListNode getIntersectionNode(ListNode headA, ListNode headB){
	ListNode p1=headA, p2=headB;
	while(p1 != p2){
		//p1走一步,若到A链尾 则转到B
		if(p1 == null) p1 = headB;
		else p1 = p1.next;
		if(p2 = null) p2 = headA;
		else p2 = p2.next;
	}
	return p1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值