程序员面试题精选100题(41)-把数组排成最小的数

// 程序员面试题精选100题(41)-把数组排成最小的数.cpp : 定义控制台应用程序的入口点。
//
/*
首先我们需要证明之前定义的比较两个数字大小的规则是有效的。一个有效的比较需要三个条件:1.自反性,即a等于a;
2.对称性,即如果a大于b,则b小于a;3.传递性,即如果a小于b,b小于c,则a小于c。现在分别予以证明。
1.      
自反性。显然有aa=aa,所以a=a。
2.       对称性。如果a小于b,则ab<ba,所以ba>ab。因此b大于a。
3.       传递性。如果a小于b,则ab<ba。当a和b用十进制表示的时候分别为l位和m位时,ab=a×10m+b,ba=b×10l+a。所以a×10m+b<b×10l+a。
于是有a×10m-a< b×10l –b,即a(10m -1)<b(10l-1)。所以a/(10l -1)<b/(10m -1)。
如果b小于c,则bc<cb。当c表示成十进制时为m位。和前面证明过程一样,可以得到b/(10m -1)<c/(10n -1)。
所以a/(10l -1)< c/(10n -1)。于是a(10n -1)<c(10l -1),所以a×10n +c<c×10l +a,即ac<ca。
所以a小于c。

*/
#include "stdafx.h"
#include <iostream>
using namespace std;
#define N 5
//char *pchar1=NULL;
//char *pchar2=NULL;
//pchar1 = new char[10];
//pchar2 = new char[10]; //why this is wrong ? because in default,the glolal vaiable is in staitc area, so it must be initialized when being created. 
//global variable can be considered as const, actually when adding static to global variable, it means it only can be used in current file, otherwise it can be called in other files.
//char *pchar1=new char[10];
//char *pchar2=new char[10];
int compare(char* str1,char* str2)
{
	char *pchar1=NULL;
	char *pchar2=NULL;
	pchar1 = new char[10];
	pchar2 = new char[10]; //why this is wrong ?
	strcpy(pchar1,str1);//the first parameter of strcpy cannot be null 
	strcat(pchar1,str2);
	strcpy(pchar2,str2);//the first parameter of strcpy cannot be null 
	strcat(pchar2,str1);
	return strcmp(pchar1,pchar2);
	//delete[] pchar1;
	//pchar1=NULL;
	//delete[] pchar2;
	//pchar2=NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
	int numarr[N] = {123,45,12,63,816};
	char *strarr[N]={NULL};
	for (int i=0;i<N;i++)
	{
		strarr[i]=new char[10];
		sprintf(strarr[i],"%d",numarr[i]);
	}
	for (int i=0;i<N;i++)
	{
		printf("%s\n",strarr[i]);
	}
	for (int i=0;i<N-1;i++)//select sort,
	{
		int k=i;
		for (int j=k+1;j<N;j++)
		{
			if (compare(strarr[k],strarr[j])>0)//select the least
			{
				k=j;//update
			}
		}
		if (k!=i)
		{
			char* temp=new char[10];
			strcpy(temp,strarr[k]);
			strcpy(strarr[k],strarr[i]);
			strcpy(strarr[i],temp);
			delete[] temp;
		}
	}
	char *allchar=new char[100];
	strcpy(allchar,"");//changed into C style so that can serve as the parameter of strcat
	for (int i=0;i<N;i++)
	{
		strcat(allchar,strarr[i]);
		strcat(allchar," ");
	}
	printf("%s\n",allchar);
	system("pause");
	for (int i=0;i<N;i++)//here is wrong because strarr is a double point
	{
		delete[] strarr[i];
		strarr[i]=NULL;
	}
	delete[] allchar;
	allchar=NULL;
	
	return 0;
}

首先我们需要证明之前定义的比较两个数字大小的规则是有效的。一个有效的比较需要三个条件:1.自反性,即a等于a;2.对称性,即如果a大于b,则b小于a;3.传递性,即如果a小于b,b小于c,则a小于c。现在分别予以证明。

1.      

自反性。显然有aa=aa,所以a=a。

2.       对称性。如果a小于b,则ab<ba,所以ba>ab。因此b大于a。

3.       传递性。如果a小于b,则ab<ba。当a和b用十进制表示的时候分别为l位和m位时,ab=a×10m+b,ba=b×10l+a。所以a×10m+b<b×10l+a。于是有a×10m-a<b×10l –b,即a(10m -1)<b(10l-1)。所以a/(10l -1)<b/(10m -1)。

如果b小于c,则bc<cb。当c表示成十进制时为m位。和前面证明过程一样,可以得到b/(10m -1)<c/(10n -1)。

所以a/(10l -1)< c/(10n -1)。于是a(10n -1)<c(10l -1),所以a×10n +c<c×10l +a,即ac<ca。

所以a小于c。

在证明了我们排序规则的有效性之后,我们接着证明算法的正确性。我们用反证法来证明。

我们把n个数按照前面的排序规则排好顺序之后,表示为A1A2A3…An。我们假设这样排出来的两个数并不是最小的。即至少存在两个x和y(0<x<y<n),交换第x个数和地y个数后,A1A2…Ay…Ax…An<A1A2…Ax…Ay…An

由于A1A2…Ax…Ay…An是按照前面的规则排好的序列,所以有Ax<Ax+1<Ax+2<…<Ay-2<Ay-1<Ay

由于Ay-1小于Ay,所以Ay-1Ay<AyAy-1。我们在序列A1A2…Ax…Ay-1Ay…An交换Ay-1和Ay,有A1A2…Ax…Ay-1Ay…An<A1A2…Ax…AyAy-1…An(这个实际上也需要证明。感兴趣的读者可以自己试着证明)。我们就这样一直把Ay和前面的数字交换,直到和Ax交换为止。于是就有A1A2…Ax…Ay-1Ay…An<A1A2…Ax…AyAy-1…An<A1A2…Ax…AyAy-2Ay-1…An<…< A1A2…AyAx…Ay-2Ay-1…An

同理由于Ax小于Ax+1,所以AxAx+1<Ax+1Ax。我们在序列A1A2…AyAxAx+1…Ay-2Ay-1…An仅仅只交换Ax和Ax+1,有A1A2…AyAxAx+1…Ay-2Ay-1…An<A1A2…AyAx+1Ax…Ay-2Ay-1…An。我们接下来一直拿Ax和它后面的数字交换,直到和Ay-1交换为止。于是就有A1A2…AyAxAx+1…Ay-2Ay-1…An<A1A2…AyAx+1Ax…Ay-2Ay-1…An<…< A1A2…AyAx+1Ax+2…Ay-2Ay-1Ax…An

所以A1A2…Ax…Ay…An<A1A2…Ay…Ax…An。这和我们的假设的A1A2…Ay…Ax…An <A1A2…Ax…Ay…An相矛盾。

所以假设不成立,我们的算法是正确的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值