今天记录了两道题,难度范围:★★~★★★★,第一道题我自己做的时候没有做出来,所以记录的是老师讲解的思路;第二题虽然我做出来了,但是没有想到官方那么巧妙的方法。
一.数字拼接 ★★★★☆
题目

思路
1.首先需要简化问题规模,即将多个数的拼接简化为两个数的拼接,将拼接的结果作为一个数又作为拼接的数字
2.GetJoinValue函数:实现两个数的拼接
2.1 利用数组保存两个数,便于后续循环内的使用,用temp保证当前处理的数字,用res存储结果
2.2 将temp的每一位数字拼接到res中:首先是value1,然后是value2。在拼接之前需要计算数字的位数,以直接按照正常顺序将数字拼接到res上,即先去数字的高位,再取低位进行拼接,所以需要用到位数count
-
GetMaxValue函数:寻找最大拼接数值。将数组元素和res作为要进行拼接的两个数,用res1、和res2保存两个数的两种不同拼接情况,最后利用res保存较大值。通过找出局部最大值就能找出全局最大值,返回即可
-
GetMinValue函数:寻找最小拼接数值。与GetMaxValue函数类似,只是最后返回最小值。
代码1
cpp
int GetJoinValue(int value1, int value2) {
//将数字保存在数组中,便于使用
int arr[] = { value1,value2 };
//创建临时变量保存数字
int temp = 0;
int res = 0;//保存拼接结果
for (int i = 0; i < 2; i++) {
temp = arr[i];
if (temp == 0) {
res *= 10;
continue;
}
int count = 0;
while (temp) {
count++;
temp /= 10;
}
temp = arr[i];
while (temp) {
res = res * 10 + temp / (int)pow(10, count - 1);
temp = temp % (int)pow(10, count - 1);
count--;
}
}
return res;
}
int GetMaxValue(int arr[], int len) {
if (len == 0) {
return -1;
}
int res = arr[0];
for (int i = 1; i < len; i++) {
int res1 = GetJoinValue(res, arr[i]);
int res2 = GetJoinValue(arr[i], res);
res = (res1 > res2) ? res1 : res2;
}
return res;
}
int GetMinValue(int arr[], int len) {
int res = arr[0];
for (int i = 1; i < len; i++) {
int res1 = GetJoinValue(res, arr[i]);
int res2 = GetJoinValue(arr[i], res);
res = (res1 < res2) ? res1 : res2;
}
return res;
}
int main() {
int arr[] = { 123,34,5,78 };
int len = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", GetMaxValue(arr, len));
printf("%d\n", GetMinValue(arr, len));
return 0;
}
代码2
因为数字拼接的结果可能超过int范围,所以可以定义一个int64表示long long int,以扩大数值范围
cpp
typedef long long int int64;
int64 GetJoinValue(int64 value1, int64 value2) {
//将数字保存在数组中,便于使用
int arr[] = { value1,value2 };
//创建临时变量保存数字
int64 temp = 0;
int64 res = 0;//保存拼接结果
for (int i = 0; i < 2; i++) {
temp = arr[i];
if (temp == 0) {
res *= 10;
continue;
}
int count = 0;
while (temp) {
count++;
temp /= 10;
}
temp = arr[i];
while (temp) {
res = res * 10 + temp / (int)pow(10, count - 1);
temp = temp % (int)pow(10, count - 1);
count--;
}
}
return res;
}
int64 GetMaxValue(int64 arr[],int len) {
int64 res = arr[0];
for (int i = 1; i < len; i++) {
int64 res1 = GetJoinValue(res, arr[i]);
int64 res2 = GetJoinValue(arr[i], res);
res = (res1 > res2) ? res1 : res2;
}
return res;
}
int64 GetMinValue(int64 arr[], int len) {
int64 res = arr[0];
for (int i = 1; i < len; i++) {
int64 res1 = GetJoinValue(res, arr[i]);
int64 res2 = GetJoinValue(arr[i], res);
res = (res1 < res2) ? res1 : res2;
}
return res;
}
int main() {
int64 arr[] = { 123,34,5,78 };
int len = sizeof(arr) / sizeof(arr[0]);
printf("%lld\n", GetMaxValue(arr, len));
printf("%lld\n", GetMinValue(arr, len));
return 0;
}
运行截图

代码3------利用函数指针
因为GetMinValue函数与GetMaxValue函数类似,只是最后利用条件运算符的地方不同,所以此处可以运用函数指针使得一个函数就能完成不同需求。
原理是将GetMaxValue函数中的条件运算符的条件改为(*comp)(res1,res2),实际运行时这个地方的函数是根据主函数调用时决定的。主函数调用Compare1选最大值,输出就是最大拼接值,反之就是最小拼接值。
主函数调用时既可以预先创建一个函数指针类型的变量指向对应函数,也可以直接调用函数。
cpp
// 实现两个数字的拼接
int64 GetJoinValue(int64 value1, int64 value2)
{
int64 res = 0;
int64 arr[2] = { value1, value2 };//用数组保存
for (int i = 0; i < 2; ++i) {
int64 temp = arr[i];//改变temp
if (temp == 0) { //数字为0→结果×10
res *= 10;
continue;
}
int count = 0;//计算数字位数
while (temp) {
count++;
temp /= 10;
}
temp = arr[i];//还原temp
while (temp) {
res = res * 10 + temp / (int)pow(10, count - 1);//将数字拼接到res后面
temp = temp % (int)pow(10, count - 1);
count--;
}
}
return res;
}
// 声明一个函数指针类型
typedef bool (*CompareInt64)(int64, int64);
//调用上面的函数实现拼接
int64 GetMaxValue(int64 arr[], int len, CompareInt64 comp)
{
if (len == 0) {
return -1;
}
int64 res = arr[0];//先将第一个数字赋给res
for (int i = 1; i < len; ++i) {
int64 res1 = GetJoinValue(res, arr[i]); //将数组当前元素加在res后面
int64 res2 = GetJoinValue(arr[i], res); //将数组res加在当前元素后面
res = (*comp)(res1, res2) ? res1 : res2;//利用函数指针改变需求:想要最大的就用Compare1,反之用Compare2
}
return res;
}
bool Compare1(int64 a, int64 b)//大于
{
return a > b ? true : false;
}
bool Compare2(int64 a, int64 b)//小于
{
return a > b ? false : true;
}
int main()
{
CompareInt64 pfunc = &Compare2;//定义函数指针类型指向函数Compare2
int64 arr[] = { 123, 34, 5, 78 };
printf("%lld\n", GetMaxValue(arr, 4, Compare1));//直接调用函数
printf("%lld\n", GetMaxValue(arr, 4, pfunc));//通过指针间接调用
return 0;
}
复杂度
时间复杂度:
空间复杂度:
tips
二.只出现一次的数字 ★★☆☆☆
题目
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
我的思路
先将数字进行排序,那么相等的两个数就会相邻,利用循环找出与相邻的那个数字不相等的数即可
代码
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
int len=nums.size();
if(len==1){
return nums[0];
}
sort(nums.begin(),nums.end());
int i=0;
for(;i<len-1;i+=2){
if(nums[i]==nums[i+1]){
continue;
}
break;
}
return nums[i];
}
};
复杂度
时间复杂度:O (n log n)
空间复杂度:O (1) 或 O (log n)------sort使用了栈空间
官方题解思路
把数组中所有元素依次异或,重复元素会相互抵消,最终剩下的就是目标元素。
代码
这是我直接更加理解的版本,官方版本在后面
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
int len=nums.size();
if(len==1){
return nums[0];
}
int res=0;
for(int i=0;i<len;i++){
res^=nums[i];
}
return res;
}
};
官方版本
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for (auto e: nums) ret ^= e;
return ret;
}
};
++说明:auto e: nums 是指「遍历 nums 中的每一个元素,把元素值赋给 e」++
复杂度
时间复杂度:O(n)
空间复杂度:O(1)