【小象算法Java版】第一节:链表(下)

leetcode 86.分隔链表

题目描述

给你一个链表和一个特定值 x ,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。

你应当保留两个分区中每个节点的初始相对位置。(传送门

示例:

输入:head = 1->4->3->2->5->2, x = 3
输出:1->2->2->4->3->5

解题思路&代码实现

在这里插入图片描述
思路和题解见:【每日一题】力扣86.分隔链表

leetcode138.复制带随机指针的链表

题目描述

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的 深拷贝。 (传送门

我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。

示例 1:

在这里插入图片描述

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:

在这里插入图片描述

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

示例 3:

在这里插入图片描述

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]

示例 4:

输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

解题思路&代码实现

使用两张map来实现
在这里插入图片描述

public Node copyRandomList(Node head) {
    
    
        //深拷贝: 完全拷贝基本数据类型和引用数据类型,安全。
        if (head == null) {
    
    
            return null;
        }
        Node newHead = new Node(-1);
        Node temp = head;
        // map1 <原链表节点,编号> 
        HashMap<Node, Integer> map1 = new HashMap<>();
        // map2 <新链表节点,编号>
        HashMap<Integer, Node> map2 = new HashMap<>();
        int len = 0;
        Node newHead2 = newHead;
        // 构造新链表,只建立next关系
        while (head != null) {
    
    
            map1.put(head, len);
            Node tmp = new Node(head.val);
            map2.put(len, tmp);
            newHead.next = tmp;
            newHead = newHead.next;
            head = head.next;
            len++;
        }
        newHead2 = newHead2.next;
        Node ans = newHead2;
        // 从新链表头节点开始建立random 关系
        while (newHead2 != null) {
    
    
            Integer index = map1.get(temp.random);//在原链表中查找random位置
            newHead2.random = map2.get(index);//在新链表找到对应原链表index位置的新节点
            newHead2 = newHead2.next;// 建立关系
            temp = temp.next;
        }
        return ans;
    }

leetcode21.合并两个有序链表

题目描述

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 (传送门

示例 1:
在这里插入图片描述

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

解题思路&代码实现

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    
    
        if (l1 == null ) {
    
    
            return l2;
        }
        if (l2 == null) {
    
    
            return l1;
        }
        ListNode newHead = new ListNode(-1);
        ListNode ans = newHead;
        while (l1 != null && l2 != null) {
    
    
            if (l1.val > l2.val) {
    
    
                newHead.next = l2;
                l2 = l2.next;
                newHead = newHead.next;
            } else {
    
    
                newHead.next = l1;
                newHead = newHead.next;
                l1 = l1.next;
            }
        }
        if (l1 == null) {
    
    
        // l2有剩余
            newHead.next = l2;
        }
        if(l2 == null) {
    
    
        //l1有剩余
            newHead.next = l1;
        }
        return ans.next;
    }

leetcode23.合并K个升序链表

题目描述

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。(传送门

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

解题思路&代码实现

方法一:暴力调用上一个题的方法
比如有k个链表,先合并1和2,合并之后的结果在和第三个合并知道最后一个。

class Solution {
    
    
    public ListNode mergeKLists(ListNode[] lists) {
    
    
        
        int len = lists.length;
        if(len == 0) {
    
    
            return null;
        }
        for (int i = 0; i < len - 1; i++) {
    
    
            lists[i+1] = mergeTwoLists(lists[i], lists[i + 1]);
        }
        return lists[len - 1];

    }
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    
    
        if (l1 == null ) {
    
    
            return l2;
        }
        if (l2 == null) {
    
    
            return l1;
        }
        ListNode newHead = new ListNode(-1);
        ListNode ans = newHead;
        while (l1 != null && l2 != null) {
    
    
            if ( l1.val > l2.val) {
    
    
                newHead.next = l2;
                l2 = l2.next;
                newHead = newHead.next;
            } else {
    
    
                newHead.next = l1;
                newHead = newHead.next;
                l1 = l1.next;
            }


        }
        if (l1 == null) {
    
    
            newHead.next = l2;
        }if(l2 == null) {
    
    
            newHead.next = l1;
        }
        
        return ans.next;

    }
    
}

方法二:优化,对称合并
在这里插入图片描述

class Solution {
    
    
    public ListNode mergeKLists(ListNode[] lists) {
    
    
        
        int len = lists.length;
        if(len == 0) {
    
    
            return null;
        }
        // 将n个链表以中间为对称,合并,即合并 
        while(len>1) {
    
    
            for (int i=0; i<len/2; i++) {
    
    
                lists[i] = mergeTwoLists(lists[i], lists[len-1-i]);
            }
            len = (len+1)/2;
        }
        return lists[0];


    }
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    
    
        if (l1 == null ) {
    
    
            return l2;
        }
        if (l2 == null) {
    
    
            return l1;
        }
        ListNode newHead = new ListNode(-1);
        ListNode ans = newHead;
        while (l1 != null && l2 != null) {
    
    
            if ( l1.val > l2.val) {
    
    
                newHead.next = l2;
                l2 = l2.next;
                newHead = newHead.next;
            } else {
    
    
                newHead.next = l1;
                newHead = newHead.next;
                l1 = l1.next;
            }


        }
        if (l1 == null) {
    
    
            newHead.next = l2;
        }if(l2 == null) {
    
    
            newHead.next = l1;
        }
        
        return ans.next;

    }
    
}

在这里插入图片描述
两种方法的时间复杂度提高还是很高的。

方法三:小根堆

class Solution {
    
    
	public ListNode mergeKLists(ListNode[] lists) {
    
    
		if(lists==null || lists.length==0) {
    
    
			return null;
		}
		//创建一个堆,并设置元素的排序方式
		PriorityQueue<ListNode> queue = new PriorityQueue(new Comparator<ListNode>() {
    
    
			public int compare(ListNode o1, ListNode o2) {
    
    
				return (o1.val - o2.val);
			}
		});
		//遍历链表数组,然后将每个链表的每个节点都放入堆中
		for(int i=0;i<lists.length;i++) {
    
    
			while(lists[i] != null) {
    
    
				queue.add(lists[i]);
				lists[i] = lists[i].next;
			}
		}
		ListNode dummy = new ListNode(-1);
		ListNode head = dummy;
		//从堆中不断取出元素,并将取出的元素串联起来
		while( !queue.isEmpty() ) {
    
    
			dummy.next = queue.poll();
			dummy = dummy.next;
		}
		dummy.next = null;
		return head.next;
	}
}


猜你喜欢

转载自blog.csdn.net/weixin_45532227/article/details/113059395