剑指Offer面试题33(java版):把数组排成最小的数

题目:输入一个正整数数组,把数组里面所有的数字拼接排成一个数,打印能拼接出的所有数字中的一个。例如输入数组{3,32,321},则打印出这3个数字能排成的最小数字321323.

这个题目最直接的做法应该是先求出这个数组中的所有数字的全排列,然后把每个排列拼接起来,最后求出排列起来的数字的最小值。求数组的排列和面试题28非常相似。根据排列组合的只是,n个数字总共有n!排列,我们再来看一下更快的算法。

这道题其实希望我们能够找到一个排序规则,数组根据这个规则排序之后能排成一个最小的数字。要确定排序的规则,就要比较两个数字,也就是给出两个数字m和n,我们需要确定一个规则判断m和n哪个应该排在前面,而不是仅仅比较这两个数字的值哪个更大。

根据题目的要求,两个数字m和n能拼接称数字mn和nm。如果mn<nm,那么我们应该打印出mn,也就是m应该拍在N的前面,我们定义此时m小于n;反之,如果nm<mn,我们定义n小于m。如果mn=nm,m等于n。

接下来考虑怎么去拼接数字,即给出数字m和n,怎么得到数字mn和nm并比较他们的大小。直接用数值去计算不难办到,但需要考虑一个潜在的问题就是m和n都在int能表达的范围内,把他们拼起来的数字mn和nm用int表示就有可能溢出了,所以这还是一个隐形的大数问题。

一个非常直观的解决大数问题的办法就是把数字转换成字符串。另外,由于把数字m和n拼接起来得到mn和nm,他们的位数肯定是相同的,因此比较它们的大小只需要按照字符串的大小的比较规则就可以了。

基于这个思路,我们实现代码:

/**
 * 把数组排成最小的数
 * 输入一个正整数数组,把数组里所有的数字拼接起来排成一个数,
 * 打印能拼接出来的所有数字中最小的一个
 */
package swordForOffer;

/**
 * @author JInShuangQi
 *
 * 2015年8月9日
 */
public class E33SortArrayForMinNumber {

	public void printMin(int[] arr){
		int[] clone = arr.clone();
		printMinNumber(clone,0,clone.length-1);
		for(int i : clone)
			System.out.print(i);
	}
	//核心+快排
	public void printMinNumber(int[] arr,int left,int right){
		if(left < right){
			int main_number = arr[right];
			int small_cur = left;
			for(int j = left;j<right;j++){
				if(isSmall(String.valueOf(arr[j]),String.valueOf(main_number))){
					int temp = arr[j];
					arr[j] = arr[small_cur];
					arr[small_cur] = temp;
					small_cur++;
				}
			}
			arr[right]= arr[small_cur];
			arr[small_cur] = main_number;
			printMinNumber(arr,0,small_cur-1);
			printMinNumber(arr,small_cur+1,right);
		}
	}
	public boolean isSmall(String m,String n){
		String left = m+n;
		String right = n+m;
		boolean result = false;
		for(int i = 0;i<left.length();i++){
			if(left.charAt(i)<right.charAt(i))
				return true;
			else
				if(left.charAt(i)>right.charAt(i))
					return false;
		}
		return result;
	}
	public static void main(String[] args){
		int arr[] = {3,32,321};
		E33SortArrayForMinNumber test = new E33SortArrayForMinNumber();
		test.printMin(arr);
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-19 00:47:11

剑指Offer面试题33(java版):把数组排成最小的数的相关文章

剑指offer面试题14(Java版):调整数组顺序使奇数位于偶数的前面

题目:输入一个整数数组.实现一个函数来调整该数组中数字的顺序.使得全部奇数位于数组的前半部分.全部偶数位于数组的后半部分. 1.基本实现: 假设不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个数字后面的全部的数字往前面挪动一位. 挪完之后在数组的末尾有一个空位.这时把该偶数放入这个空位. 因为没碰到一个偶数就须要移动O(n)个数字.因此总的时间复杂度是O(n2).可是,这样的方法不能让面试官惬意.只是假设我们在听到题目之后立就可以以说出这个解法,

剑指offer 面试题33 把数组排成最小的数

题目链接: 剑指offer 题目链接: 把数组排成最小的数, 例如{3, 32, 321} 输出: 321323 解题思路: 我现在已经知道正确答案了, 就是没有办法去证明, 先去开会, 在开会的时候再去想. 代码: #include <iostream> #include <cstdio> #include <string> #include <vector> #include <cstring> #include <iterator&g

《剑指Offer》——Singleton(Java版)

1.单例模式的定义 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 2.单例模式的特点 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例. 3.单例模式的Java代码 单例模式分为懒汉式(需要才去创建对象)和饿汉式(创建类的实例时就去创建对象). 4.饿汉式 在静态代码块实例对象 //在静态代码块实例对象 public class Singleton { private static Singleton singleton

剑指offer 面试题33—把数组排成最小的数

题目: 输入一个正整数数组,把数组里面的所有数字连接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3, 32,  321},则打印这三个数字能排成的最小数字321323. 基本思想:O(nlogn) 两个数字m和n能拼接数字mn和nm.如果mn<nm,那么我们应该打印出mn,也就是m应该排在n的前面,我们定义此时m小于n:反之,如果nm<mn,我们定义n小于m.如果mn=nm,m等于n. 如对321和32,排序为32132<32321,所以321<32(这个小于

剑指offer 面试题38—数字在排序数组中出现的次数

题目: 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 解法一:O(n) 顺序遍历 解法二:O(logn) 用二分查找,分别找出第一个3,和最后一个3的位置,然后计算个数. #include <stdio.h> int GetFirstK(int* data,int length,int k,int start,int end) { if(start > end) return -1; int m

剑指Offer面试题:2.二维数组中的查找

一.题目:二维数组中的查找 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 例如下面的二维数组就是每行.每列都递增排序.如果在这个数组中查找数字7,则返回true:如果查找数字5,由于数组不含有该数字,则返回false. 二.解题思路 首先选取数组中右上角的数字.如果该数字等于要查找的数字,查找过程结束:如果该数字大于要查找的数字,剔除这个数字所在的列:如果该数字小于要查

《剑指offer》— JavaScript(6)旋转数组的最小数字

旋转数组的最小数字 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. NOTE:给出的所有元素都大于0,若数组大小为0,请返回0. 实现代码 function minNumberInRotateArray(rotateArray) { var len=rotateArray.length; if(len== 0 || !r

二叉树层次遍历(剑指Offer面试题32:从上到下打印二叉树)

图1所示为二叉树的层次遍历,即按照箭头所指方向,按照1.2.3的层次顺序,对二叉树每个节点进行访问 (此图反映的是自左至右的层次遍历,自右至左的方式类似). 要进行层次遍历,需要建立一个队列.先将二叉树头节点入队列,然后出队列,访问该节点, 如果它有左子树,则将左子树的根结点入队:如果它有右子树,则将右子树的根结点入队.然后出队列,对出队节点访问, 如此反复直到队列为空为止. 1 import java.util.*; 2 class TreeNode 3 { 4 int val; 5 Tree

剑指offer面试题29:数组中出现次数超过一半的数字

题目:数组中有一个数字出现的次数超过数组长度的一般,请找出这个数字,例如输入一个长度为9的数组(1,2,3,2,2,2,5,4,2,).由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. 个人第一眼想法是通过一个sort函数,再判断中间那数出现次数,只要出现多于n/2,就直接输出. 一般来说,最为直观的算法面试官都不会满意,那么有没有更优的算法呢? 这种算法是受快速排序算法的启发.在随机快速排序算法中,我们现在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中的数字小的数字