【LeetCode】23. Merge k Sorted Lists 基于Java的解法

23. Merge k Sorted Lists

Total Accepted: 88102 Total Submissions: 372066 Difficulty: Hard

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

【题意】

将K个已经排序的链表合并成一个排序的链表,分析并描述所用算法的复杂度。

【分析】

解法一:基于“二分”思想的归并排序

     初见之下,最容易想到的方法是“归并排序”(Merging Sort):将两个或两个以上的有序表组合成一个新的有序表,无论是顺序存储结构还是链式存储结构,对于任何两个长度分别为m和n的有序表,其组合都可在O(m+n)的时间复杂度量级上完成。对于K个有序表,假设共有N个元素,且这些有序表初始状态都不为空,每个有序表平均拥有N/K个元素。最常用的方法是采用“二分”的思想进行两两合并:第一轮循环,有序表lists[0]与lists[(K+1)/2],lists[1]与lists[(K+1)/2+1],lists[2]与lists[(K+1)/2+2]....,lists[K/2-1]与lists[K-1]。这样K个有序表就被组合成了K/2个有序表;第二轮循环后将减少为K/4个有序表;直到组合成一个具有N个元素的有序表。总的时间复杂度:O(NKlogK)

解法二:基于优先级队列的“堆排序”

   堆(Heap)的定义如下:n个元素的序列{k1,k2,k3,...,kn}当且仅当满足下列关系时,称为


   其中前者称为最小堆,后者称为最大堆。在Java中,堆是一种可以自我调整的二叉树,对于最小堆来说,对树执行删除和添加操作,可以让最小元素移动到根节点。在Java中,优先级队列(Priority Queue)便采用了“堆”这种数据结构,PriorityQueue是一个泛型类,它可以保存实现了Comparable接口的类对象,也可以保存在构造器中提供比较器的对象(优先级队列实现排序中也需要比较)。

     基于优先级队列,我们可以将K个链表的头结点全部添加到队列,由于优先级队列采用了最小堆数据结构,堆顶为队列的最小元素,我们将其取出添加到结果链表中,取出元素对应的链表下移一个节点,并将这个节点添加到优先级队列中;然后我们继续取出堆顶元素,...,直到优先级队列为空,那么其中所有元素取尽,K个链表的元素已经全部排序到结果链表。

【程序】

 一、基于“二分”思想的归并排序(Java实现)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution
{
public ListNode mergeKLists(ListNode[] lists)
	{
		int len=lists.length;
		
		if(lists==null||len==0)
			return null;
		if(len==1)
			return lists[0];
		
		while(len>1)//基于“二分”思想进行链表的两两组合
		{
			int mid=(len+1)/2;//二分
		    for(int i=0;i<len/2;i++)
		    {
		    	lists[i]=mergeTwoLists(lists[i],lists[i+mid]);
		    }
		    len=mid;
		}
		return lists[0];
	}
	//有序链表的组合,L1和L2为头结点,归并排序的核心思想
	public ListNode mergeTwoLists(ListNode L1,ListNode L2)
	{
		if(L1==null)return L2;
		if(L2==null)return L1;
		
		ListNode head=new ListNode(0);//保存结果的链表,头结点初始化
		ListNode phead=head;
		
		while(L1!=null&&L2!=null)//两个链表归并排序
		{
			if(L1.val <=L2.val)
			{
				phead.next=L1;//接入结果链表
				phead=phead.next;//移动指针
				L1=L1.next;
			}
			else
			{
				phead.next=L2;
				phead=phead.next;
				L2=L2.next;
			}
		}
		if(L1!=null)
			phead.next=L1;
		else
			phead.next=L2;
		
		return head.next;//初始化的第一个节点不属于结果
	}
}

运行结果:

 二、基于优先级队列的“堆排序”(Java实现)

class ListNode implements Comparable<ListNode>
{
	int value;
	ListNode next;
	ListNode(int val)
	{
		value=val;
	}
	
	public int compareTo(ListNode other)
	{
		return value-other.value;
	}
}
//用优先级队列实现组合排序,其中优先级队列采用的数据结构为“最小堆”
class Solution
{
	public ListNode mergeKLists(ListNode[] lists)
	{
		if(lists==null||lists.length==0)
			return null;
		if(lists.length==1)
			return lists[0];
		
		 
		PriorityQueue<ListNode> PQ=new PriorityQueue<ListNode>();
		
		ListNode head=new ListNode(0);
		ListNode phead=head;
		
		for(ListNode list:lists)
		{
			if(list!=null)
				PQ.offer(list);
		}
		while(!PQ.isEmpty())
		{
			ListNode temp=PQ.poll();
			phead.next=temp;
			phead=phead.next;
			
			if(temp.next!=null)
				PQ.offer(temp.next);
		}
		return head.next;
	}
}
运行结果:




  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 可以使用Java中的排序功能来实现。可以使用Arrays.sort()函数,将列表中的元素按照字母顺序排序,或者使用Collections.sort()函数,将列表中的元素按用户指定的排序规则排序。 ### 回答2: 为了实现LeetCode 2561题(Rearranging Fruits)的要求,需要使用Java编程语言。主要思路是遍历给定的水果数组,同时用一个哈希表来记录每个水果出现的次数。然后根据题目要求,重新排列水果使得相同类型的水果尽可能接近,并且按照出现次数的非递增顺序排序。 具体实现步骤如下: 1. 创建一个HashMap来存储每个水果的出现次数。遍历给定的水果数组,如果该水果已经存在于HashMap中,则将其出现次数加1;否则,将该水果添加到HashMap,并将其出现次数初始化为1。 2. 创建一个ArrayList来存储已经排列好的水果。通过HashMap的entrySet方法获取到每种水果和它的出现次数,然后将这些entry按照出现次数的非递增顺序进行排序。 3. 遍历排序好的entry集合,根据每个水果的出现次数,在ArrayList中连续添加相应数量的水果。 4. 返回排列好的水果数组。 以下是Java代码的示例实现: ```java import java.util.*; class Solution { public String[] rearrange(String[] fruits) { HashMap<String, Integer> fruitCountMap = new HashMap<>(); // 统计每个水果的出现次数 for (String fruit : fruits) { if (fruitCountMap.containsKey(fruit)) { fruitCountMap.put(fruit, fruitCountMap.get(fruit) + 1); } else { fruitCountMap.put(fruit, 1); } } ArrayList<Map.Entry<String, Integer>> sortedEntries = new ArrayList<>(fruitCountMap.entrySet()); // 根据出现次数进行非递增排序 Collections.sort(sortedEntries, new Comparator<Map.Entry<String, Integer>>() { public int compare(Map.Entry<String, Integer> entry1, Map.Entry<String, Integer> entry2) { return entry2.getValue().compareTo(entry1.getValue()); } }); ArrayList<String> rearrangedFruits = new ArrayList<>(); // 根据出现次数连续添加水果 for (Map.Entry<String, Integer> entry : sortedEntries) { String fruit = entry.getKey(); int count = entry.getValue(); for (int i = 0; i < count; i++) { rearrangedFruits.add(fruit); } } return rearrangedFruits.toArray(new String[0]); } } ``` 使用以上代码,可以对给定的水果数组进行重新排列,使得相同类型的水果尽可能接近,并且按照出现次数的非递增顺序进行排序。返回的结果就是排列好的水果数组。 ### 回答3: 题目要求将一个字符串中的水果按照特定规则重新排列。我们可以使用Java来实现这个问题。 首先,我们需要定义一个函数来解决这个问题。 ```java public static String rearrangeFruits(String fruits) { // 将字符串转换为字符数组方便处理 char[] fruitArray = fruits.toCharArray(); // 统计每种水果的数量 int[] fruitCount = new int[26]; for (char fruit : fruitArray) { fruitCount[fruit - 'a']++; } // 创建一个新的字符数组来存储重新排列后的结果 char[] rearrangedFruitArray = new char[fruitArray.length]; // 逐个将水果按照规则放入新数组中 int index = 0; for (int i = 0; i < 26; i++) { while (fruitCount[i] > 0) { rearrangedFruitArray[index++] = (char) ('a' + i); fruitCount[i]--; } } // 将字符数组转换为字符串并返回 return new String(rearrangedFruitArray); } ``` 上述代码中,我们首先将字符串转换为字符数组,并使用一个长度为26的数组来统计每一种水果的数量。然后,我们创建一个新的字符数组来存储重新排列后的结果。 接下来,我们利用双重循环将每一种水果按照规则放入新数组中。最后,我们将字符数组转换为字符串并返回。 例如,如果输入字符串为`"acbba"`,则经过重新排列后,输出结果为`"aabbc"`。 这样,我们就用Java实现了题目要求的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jin_Kwok

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值