33.把数组排成最小数
问题描述:
输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。例如输入数组{32, 321},则输出这两个能排成的最小数字32132。请给出解决问题的算法,并证明该算法。
思路:
先将整数数组转为字符串数组,然后字符串数组进行排序,最后依次输出字符串数组即可。这里注意的是字符串的比较函数需要重新定义,不是比较a和b,而是比较ab与 ba。如果ab < ba,则a < b;如果ab > ba,则a > b;如果ab = ba,则a = b。比较函数的定义是本解决方案的关键。这道题其实就是希望我们能找到一个排序规则,根据这个规则排出来的数组能排成一个最小的数字。
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
using namespace std;
bool compare(const string& str1, const string &str2)
{
string s1=str1+str2;
string s2=str2+str1;
return s1<s2; //如果是求最大,则把小于改成大于即可
}
//void ComArrayMin(int *pArray, int num)
//{
// int i;
// string *pStrArray=new string[num];
// for(i=0; i<num; i++)
// {
// stringstream stream;
// stream<<pArray[i];
// stream>>pStrArray[i];
// }
// sort(pStrArray, pStrArray+num, compare);
// for(i=0; i<num; i++)
// cout<<pStrArray[i];
// cout<<endl;
// delete[] pStrArray;
//}
void ComArrayMin(int *pArray, int num)
{
int i;
vector<string> vec;
for(i=0; i<num; i++)
{
vec.push_back(to_string(pArray[i]));
}
sort(vec.begin(),vec.end(), compare);
for(i=0; i<num; i++)
cout<<vec[i];
cout<<endl;
}
int main()
{
int Num;
cin>>Num;
int *pArray=new int[Num];
for(int i=0; i<Num; i++)
cin>>pArray[i];
ComArrayMin(pArray, Num);
return 0;
}
参考链接:https://blog.csdn.net/cxllyg/article/details/7659525
34.丑数
题目描述:
-
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。
习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
- 输入:
-
输入包括一个整数N(1<=N<=1500)。
- 输出:
-
可能有多组测试数据,对于每组数据,
输出第N个丑数。
-
思路: 将查找的丑数按从小到大的顺序排好序,注意每个丑数毕为前面的丑数乘以2、3或5得到的;把现有最大丑数记为M,则把第一个乘以2后大于M的结果记为M2,同理,把每个丑数乘以3和5 ,得到的第一个大于M的结果为M3和M5,那么下一个丑数必为M2/M3/M5这三个数的最小者。
//丑数
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int GetUglyNumber_Solution(int index) {
if(index <=0)
return 0;
vector<int>num(index);
num[0] =1;
int t2= 0, t3 = 0, t5 = 0, i;
for (i= 1; i < index; ++i)
{
num[i] =min(num[t2] * 2, min(num[t3] * 3, num[t5] * 5)); //M2/M3/M5这三个数的最小者
if(num[i] == num[t2] * 2)t2++; //如果最小的这个数是M2,则将当前数组下标前移,继续比较,下面同理
if(num[i] == num[t3] * 3)t3++;
if(num[i] == num[t5] * 5)t5++;
}
return num[index - 1];
}
int main()
{
int x;
cout <<"输入一个数:";
while (cin >> x)
{
cout <<"第"<< x <<"个丑数为"<<GetUglyNumber_Solution(x)<<endl;
cout <<"输入一个数:";
}
return 0;
}
参考链接:https://blog.csdn.net/liqing1310200526/article/details/79659726
https://www.cnblogs.com/xing901022/p/3796777.html
40.数组中只出现一次的数字
题目描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。- 输入:
-
每个测试案例包括两行:第一行包含一个整数n,表示数组大小。2<=n <= 10^6。第二行包含n个整数,表示数组元素,元素均为int。
- 输出:
- 对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。
- 样例输入:
-
8 2 4 3 6 3 2 5 5
- 样例输出:
-
4 6
思路:利用异或去重的原理。但这里是有两个只出现一次的数字,我们便要想办法把他分为两个子数组,每个子数组中包含一个只出现一次的数字,其他的数字都出现了两次。剑指offer上的思路很巧妙,依然从头到尾异或所有的数字,这样得到的结果实际上就是两个只出现了一次的数字异或的结果,我们在异或后的结果中找出其二进制中最右边为1的位,该位既然为1,说明异或的两个数字对应的该位肯定不同,必定一个为1,一个为0,因此我们可以考虑根据此位是否为1来划分这两个子数组,这样两个只出现一次的数字就分开了,但我们还要保证出现两次的数字都分到同一个子数组中,肯定不能两个重复的数字分在两个不同的子数组中,这样得到的结果是不对的,很明显,相同的数字相同的位上的值是相同的,要么都为1,要么都为0,因此我们同样可以通过判断该位是否为1来将这些出现两次的数字划分到同一个子数组中,该位如果为1,就分到一个子数组中,如果为0,就分到另一个子数组中。这样就能保证每个子数组中只有一个出现一次的数字,其他的数字都出现两次,分别全部异或即可得到这两个只出现一次的数字。时间复杂度为O(n)。
/*数字中第一次出现1的位置,从右到左,由低位到高位*/
unsigned int FindFirstBitIs1(int num)
{
int index = 0;
while((num & 1) == 0 && (index < 8 * sizeof(int)))
{
num = num >> 1;
index++;
}
return index;
}
/*数字在index位置上的值是否为1*/
bool IsBit1(int num, int index)
{
num = num >> index;
return(num & 1);
}
/*查找数组中只出现一次的数字*/
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2)
{
if(data.empty() || data.size() < 2 || num1 == NULL || num2 == NULL)
return;
int result = 0;
//将所有数字相互异或
for(int i = 0; i < data.size(); i++)
result ^= data[i];
//找到结果中1第一次出现的位置
unsigned int indexOf1 = FindFirstBitIs1(result);
*num1 = *num2 = 0;
for(int j = 0; j < data.size(); j++)
{
//根据index位置上的值是否为1将数组分为两部分
//并将两部分数字分别互相异或
//两部分数字异或最终的结果分别为数组中只出现一次的两个数字
if(IsBit1(data[j], indexOf1))
*num1 ^= data[j];
else
*num2 ^= data[j];
}
}
参考链接:https://blog.csdn.net/ns_code/article/details/27649027
https://blog.csdn.net/zengzhen_CSDN/article/details/50571083