《剑指offer》-[第5章:优化时间与空间效率-5.1:时间效率]-题33:把数组排成最小的数

本文探讨了如何通过动态规划解决整型数组拼接成最小数的问题,详细介绍了算法的思路与实现,包括状态转移方程及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、问题描述

输入一个整型数组,把数组中的所有数拼接起来组成一个拼接数,将所有拼接数中最小的那个打印出来。例如输入数组{3,32,321}\{3,32,321\}{332321},则打印出的这3个数的最小拼接数是321323。

2、解题思路

  • 边界条件:(1)输入数组为空指针或空数组;
  • 思路1:这道题可以采用动态规划来做。假设N[i]N[i]N[i]表示使用数组中iii个数排成的最小数。我们首先从几个例子来分析最优子结构:
  • (1)例1:{3,32,321}\{3,32,321\}{332321}
  • 为了便于观察,我们不将数直接拼接,而是使用“-”间隔开来
  • N[1]N[1]N[1](使用数组中1个数排成的最小数):{3}\{3\}{3}
  • N[2]N[2]N[2](使用数组中的2个数排成的最小数):{32−3}\{32-3\}{323}
  • N[3]N[3]N[3](使用数组中的3个数排成的最小数):{321−32−3}\{321-32-3\}{321323}
  • (2)例2:{1,2,3}\{1,2,3\}{123}
  • N[1]N[1]N[1](使用数组中1个数排成的最小数):{1}\{1\}{1}
  • N[2]N[2]N[2](使用数组中的2个数排成的最小数):{1−2}\{1-2\}{12}
  • N[3]N[3]N[3](使用数组中的3个数排成的最小数):{1−2−3}\{1-2-3\}{123}
  • 从这两个例子中可以看出,N[i]N[i]N[i]可以通过N[i−1]N[i-1]N[i1]构造得到,在构造N[i]N[i]N[i]时,每次都从未在N[i−1]N[i-1]N[i1]中出现的剩余数中选择一个最小的数,然后将这个最小的数拼在N[i−1]N[i-1]N[i1]的开头或末尾。相应的状态转移方程如下:
  • N[i]={numberif i=0min(N[i−1]+number,number+N[i−1]if i>0N[i]= \begin{cases} number & if \ i=0 \\ min(N[i-1] + number,number + N[i-1] & if\ i > 0 \end{cases}N[i]={numbermin(N[i1]+numbernumber+N[i1]if i=0if i>0
    其中,numbernumbernumber表示未在N[i−1]N[i-1]N[i1]出现的数中的最小数,N[i−1]+numberN[i-1] + numberN[i1]+number表示将number拼接在N[i−1]N[i-1]N[i1]的结尾,而number+N[i−1]number + N[i-1]number+N[i1]相反。这种方法的时间复杂度为O(n2)O(n^{2})O(n2),耗时的操作是查找最小的数number和两个字符串的大小比较。

3、代码实现

import java.util.ArrayList;

public class Problem_33 {
    public String PrintMinNumber(int [] numbers) {

        if(numbers == null || numbers.length <=0){
            return "";
        }

        ArrayList<Integer> numbers_back = new ArrayList<Integer>();
        for(int j = 0; j<numbers.length;j++){
            numbers_back.add(numbers[j]);
        }
        String [] minPermutation = new String[numbers.length];
        for(int i = 0; i < numbers.length; i++){
            Integer minx = this.findMinOfOthers(numbers_back);
            String minxs = String.valueOf(minx);
            if(i==0){
                minPermutation[i]=minxs;
            }
            else {
                String candidate1 = minPermutation[i-1] + minxs;
                String candidate2 = minxs + minPermutation[i-1];
                if(candidate1.compareTo(candidate2) < 0){
                    minPermutation[i] = candidate1;
                }
                else {
                    minPermutation[i] = candidate2;
                }
            }
            numbers_back.remove(minx);
        }
        System.out.println("result="+minPermutation[numbers.length - 1]);
        return minPermutation[numbers.length - 1];

    }
    private int findMinOfOthers(ArrayList<Integer> numbers){
        Integer minx = numbers.get(0);
        for(int k = 1; k < numbers.size(); k++){
            if (numbers.get(k) < minx){
                minx = numbers.get(k);
            }
        }
        return minx;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Albert_YuHan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值