文章目录
最大的leftMax与rightMax之差的绝对值
题目
给定一个长度为N(N>1)的整型数组arr,可以划分为左右两个部分,左部分为arr[0…K],右部分为arr[K+1…N-1],K可以取值的范围是[0, N-2]。求这么多划分方案中,左部分中的最大值减去右部分最大值的绝对值中,最大是多少。
举例:[2, 7, 3, 1, 1],当左部分为[2, 7],右部分为[3, 1, 1]时,左部分最大值减去右部分最大值绝对值为4.左部分为[2,7,3],右部分为[1,1]时,左部分最大值减去右部分最大值绝对值为6.还有很多划分方案,但最终返回6.
代码
#include<iostream>
#include<algorithm>
using namespace std;
int maxAbs1(int* arr, int len)
{
int res = INT_MIN;
int maxLeft = 0;
int maxRight = 0;
for (int i = 0; i < len - 1; i++)
{
maxLeft = INT_MIN;
for (int j = 0; j <= i; j++)
maxLeft = max(arr[j], maxLeft);
maxRight = INT_MIN;
for (int j = i + 1; j < len; j++)
maxRight = max(arr[j], maxRight);
res = max(abs(maxLeft - maxRight), res);
}
return res;
}
int maxAbs2(int* arr, int len)
{
int* lArr = new int[len];
int* rArr = new int[len];
lArr[0] = arr[0];
rArr[len - 1] = arr[len - 1];
for (int i = 1; i < len; i++)
lArr[i] = max(lArr[i - 1], arr[i]);
for (int j = len - 2; j >= 0; j--)
rArr[j] = max(rArr[j + 1], arr[j]);
int Max = 0;
for (int i = 0; i < len - 1; i++)
Max = max(Max, abs(lArr[i] - rArr[i + 1]));
return Max;
}
//找到数组最大值之后,只需要确定最大值属于哪一部分,若属于左半部分
//只要右半部分最大值尽量小;如果是右半部分,则左半部分最大值尽量小即可
int maxAbs3(int* arr, int len)
{
int Max = INT_MIN;
for (int i = 0; i < len; i++)
Max = max(arr[i], Max);
return Max - min(arr[0], arr[len - 1]);
}
int main()
{
int len;
cin >> len;
int* input = new int[len];
for (int i = 0; i < len; i++)
cin >> input[i];
int res1 = maxAbs1(input, len);
int res2 = maxAbs2(input, len);
int res3 = maxAbs3(input, len);
cout << res1 << " " << res2 << " " << res3 << endl;
getchar();
return 0;
}
路径数组变为统计数组
题目
给定一个路径数组paths,表示一张图,paths[i] =j 代表城市i连向城市j,如果paths[i] = i,则表示i城市是首都,一张图中只能有一个首都求途中除首都指向自己之外不会有环。如paths=[9, 1, 4, 9, 0 ,4, 8 , 9, 0, 1],如图所示
由数组表示的图可知,城市1为首都,距离为0,离首都距离为1的城市只有9,离首都距离为2的城市有0,3,和7,离首都距离为3的城市有城市4和8,离首都距离为4的城市有2,5和6.所以距离0的城市有1座,距离为1的城市有1座,距离为2的城市有3座,距离为3的城市有2座,距离为4的城市有3座。那么统计数组为nums=[1,1,3,2,3,0,0,0,0,0],nums[i]==j表示距离为i的城市有j座。要求实现函数将路径数组paths在原数组上进行调整,使之成为nums数组。
若paths长度为N,时间复杂度要求为O(N),额外空间复杂度为O(1).
代码
#include<iostream>
#include<algorithm>
using namespace std;
void pathToDis(int* &paths, int len)
{
int cap = 0;
for (int i = 0; i < len; i++)
{
if (paths[i] == i)
cap = i;
else if (paths[i] > -1)
{
int curI = paths[i];
paths[i] = -1;
int preI = i;
while (paths[curI] != curI)
{
if (paths[curI] > -1)
{
int nextI = paths[curI];
paths[curI] = preI;
preI = curI;
curI = nextI;
}
else
break;
}
int value = paths[curI] == curI ? 0 : paths[curI];
while (paths[preI] != -1)
{
int lastPreI = paths[preI];
paths[preI] = --value;
curI = preI;
preI = lastPreI;
}
paths[preI] = --value;
}
}
paths[cap] = 0;
}
void disToNums(int* &disArr, int len)
{
for (int i = 0; i < len; i++)
{
int index = disArr[i];
if (index < 0)
{
disArr[i] = 0; //important
while (true)
{
index = -index;
if (disArr[index] > -1)
{
disArr[index]++;
break;
}
else
{
int nextIndex = disArr[index];
disArr[index] = 1;
index = nextIndex;
}
}
}
}
disArr[0] = 1;
}
void pathsToNums(int* &paths, int len)
{
if (paths == NULL || len < 1)
return;
pathToDis(paths, len);
disToNums(paths, len);
}
int main()
{
int len;
cin >> len;
int* path = new int[len]; //[9 1 4 9 0 4 8 9 0 1]
for (int i = 0; i < len; i++)
cin >> path[i];
pathsToNums(path, len);
for (int i = 0; i < len; i++)
cout << path[i] << " ";
cout << endl;
getchar();
return 0;
}
正数数组的最小不可组成和
题目
给定一个正数数组arr,其中所有的数为整数,一下是最小不可组成和的概念
1、把arr每个子集的所有元素加起来会出现很多之,最小记为min,最大记为max。
2、在区间[min,max]上,如果有数不可以被arr某个子集相加得到,那么其中最小的那个数是arr的最小不可组成和。
3、在区间[min,max]上,如果所有的数都可以被arr的某个子集相加得到,那么max+1是arr的最小不可组成和。
请写函数返回正数数组arr的最小不可组成和。
进阶题目:如果已知正数数组中肯定有1这个数,能否更快得到最小不可组成和?
代码
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
void process(int* arr, int len, int i, int sum, set<int> &s)
{
if (i == len)
{
s.insert(sum);
return;
}
process(arr, len, i + 1, sum, s);
process(arr, len, i + 1, sum + arr[i], s);
}
int unformedSum1(int* arr, int len)
{
if (arr == NULL || len < 1)
return 1;
set<int> s;
process(arr, len, 0, 0, s);
int Min = INT_MAX;
int Max = INT_MIN;
for (int i = 0; i < len; i++)
Min = min(Min, arr[i]);
set<int>::iterator it;
for (it = s.begin(); it != s.end(); it++)
Max = max(Max, *it);
for (int i = Min + 1; i <= Max; i++)
if (s.find(i) == s.end())
return i;
return Max + 1;
}
int unformedSum2(int* arr, int len)
{
if (arr == NULL || len < 1)
return 1;
int sum = 0;
int Min = INT_MAX;
for (int i = 0; i < len; i++) {
sum += arr[i];
Min = min(Min, arr[i]);
}
bool* dp = new bool[sum + 1];
for (int i = 0; i <= sum; i++)
dp[i] = false;
dp[0] = true;
for (int i = 0; i < len; i++)
{
for (int j = sum; j >= arr[i]; j--)
dp[j] = dp[j - arr[i]] ? true : dp[j];
}
for (int i = Min; i < sum + 1; i++)
{
if (!dp[i])
return i;
}
return sum + 1;
}
int unformedSum3(int* arr, int len)
{
if (arr == NULL || len < 1)
return 0;
sort(arr, arr + len);
int range = 0;
for (int i = 0; i < len; i++)
{
if (arr[i] > range + 1)
return range + 1;
else
range += arr[i];
}
return range + 1;
}
int main()
{
int len;
cin >> len;
int* arr = new int[len];
for (int i = 0; i < len; i++)
cin >> arr[i];
int res1 = unformedSum1(arr, len);
int res2 = unformedSum2(arr, len);
int res3 = unformedSum3(arr, len);
cout << res1 << " " << res2 << " " << res3 << endl;
getchar();
return 0;
}
一种字符串和数字的对应关系
题目
一个char类型的数组chs,其中所有的字符都不同。
例如,chs=[‘A’,‘B’,‘C’,…‘Z’],则字符串与整数的对应关系如下:
A,B…Z,AA,AB…AZ,BA,BB…ZZ,AAA…ZZZ,AAAA…
1,2…26,27,28…52,53,54…702,703…18278,18279…
例如,chs=[‘A’,‘B’,‘C’],则字符串与整数对应关系如下:
A,B,C,AA,AB…CC,AAA…CCC,AAAA…
1,2,3, 4, 5… 12, 13… 39, 40…
给定一个数组chs,实现根据对应关系完成字符串与整数相互转换的两个函数。
代码
#include<iostream>
#include<vector>
#include<string>
using namespace std;
char getKthCharAtChs(char* chs, int len, int k)
{
if (k < 1 || k > len)
return 0;
return chs[k - 1];
}
string getString(char* chs, int len, int n)
{
if (chs == NULL || len < 1 || n < 1)
return "";
int cur = 1;
int base = len;
int l = 0;
while (n > cur)
{
l++;
n -= cur;
cur *= base;
}
char* res = new char[l + 1];
int index = 0;
int nCur = 0;
do {
cur /= base;
nCur = n / cur;
res[index++] = getKthCharAtChs(chs, len, nCur + 1);
n %= cur;
} while (index != l);
string sRes;
for (int i = 0; i < l; i++)
sRes += res[i];
return sRes;
}
int getNthFromChar(char* chs, char ch)
{
int res = -1;
int len = strlen(chs);
for (int i = 0; i != len; i++)
{
if (chs[i] == ch)
{
res = i + 1;
break;
}
}
return res;
}
int getNum(char* chs, int cLen, string str)
{
if (chs == NULL || strlen(chs) == 0)
return 0;
int len = str.size();
char* strc = new char[len + 1];
strcpy(strc, str.c_str());
strc[len] = '\0';
int base = cLen;
int cur = 1;
int res = 0;
for (int i = len - 1; i >= 0; i--)
{
res += getNthFromChar(chs, strc[i]) * cur;
cur *= base;
}
return res;
}
int main()
{
int len, val;
cin >> len >> val;
char* input = new char[len + 1];
for (int i = 0; i < len; i++)
cin >> input[i];
input[len] = '\0'; //important
string res = getString(input, len, val);
int res1 = getNum(input, len, res);
cout << res << endl;
cout << res1 << endl;
getchar();
return 0;
}
1到n中1出现的次数
题目
给定一个整数n,返回从1到n的数字中1出现的个数。
例如:n=11, 1~n为1,2,3,4,5,6,7,8,9,10,11.那么1出现的次数为4,返回4
剑指offer中有出现一样的题目,最优解是相同的
代码
#include<iostream>
#include<algorithm>
using namespace std;
int get1Nums(int num)
{
int res = 0;
while (num != 0)
{
if (num % 10 == 1)
res++;
num /= 10;
}
return res;
}
int sol1(int num)
{
if (num < 1)
return 0;
int cnt = 0;
for (int i = 1; i <= num; i++)
cnt += get1Nums(i);
return cnt;
}
int powBase10(int base)
{
return pow(10, base);
}
int getLenOfNum(int num)
{
int len = 0;
while (num != 0)
{
len++;
num /= 10;
}
return len;
}
int sol2(int num)
{
if (num < 1)
return 0;
int len = getLenOfNum(num);
if (len == 1)
return 1;
int tmp = powBase10(len - 1);
int first = num / tmp;
int firstOneNum = first == 1 ? num % tmp + 1 : tmp;
int otherOneNum = first * (len - 1) * (tmp / 10);
return firstOneNum + otherOneNum + sol2(num % tmp);
}
int main()
{
int num;
cin >> num;
int res1 = sol1(num);
int res2 = sol2(num);
cout << res1 << " " << res2 << endl;
getchar();
return 0;
}
从N个数中等概率打印M个数和判断一个数字是否为回文数
题目
1、给定一个长度为N且没有重复元素的数组arr和一个整数N,实现函数等概率随机打印arr中的M个数。
要求:相同的数不重复打印;时间复杂度为O(M),额外空间复杂度为O(1);可以改变arr数组;
2、定义回文数概念如下:
如果一个非负数左右完全对应,则该数是回文数,如121,22等;
如果一个负数的绝对值左右完全对应,也是回文数,如-121,-22等;
给定一个32位整数num,判断num是否为回文数
代码
#include<iostream>
#include<algorithm>
using namespace std;
/*每次将打印的数保存于数组的最后一个位置,将范围缩小*/
void swap(int* &arr, int index1, int index2)
{
int tmp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = tmp;
}
void printRandM(int* arr, int len, int m)
{
if (arr == NULL || len < 1 || m < 0)
return;
m = min(len, m);
int cnt = 0;
int i = 0;
while (cnt < m)
{
i = (int)(rand() % (len - cnt));
cout << arr[i] << " ";
swap(arr, len - cnt - 1, i); //注意缩减数组大小后数组位置
cnt++;
}
cout << endl;
}
/*判断数组是否为回文数*/
bool isPalindrome(int n)
{
if (n == INT_MIN)
return false;
n = abs(n);
int help = 1;
while (n / help >= 10)
help *= 10;
while (n != 0)
{
if (n / help != n % help)
return false;
n = (n % help) / 10;
help /= 100;
}
return true;
}
int main()
{
int len, m;
cin >> len >> m;
int* input = new int[len];
for (int i = 0; i < len; i++)
cin >> input[i];
printRandM(input, len, m);
getchar();
return 0;
}
在有序旋转数组中找到最小值以及在有序旋转数组中找到一个数
题目
有序数组arr可能经过一次旋转处理,也可能没有,且arr可能存在重复的数。例如,有序数组[1,2,3,4,5,6,7]可以旋转处理成[4,5,6,7,1,2,3]等。给定一个可能旋转过的有序数组arr,返回arr中的最小值。
给定一个可能旋转过的有序数组arr,再给定一个数num,返回arr中是否含有num。
代码
#include<iostream>
#include<algorithm>
using namespace std;
/*在有序旋转数组中找到最小值(旋转数组中可能有重复值)*/
int findMinValue(int* arr, int len)
{
if (arr == NULL || len < 1)
return -1;
int low = 0;
int high = len - 1;
int mid = 0;
while (low < high)
{
if (low == high - 1)
break;
if (arr[low] < arr[high])
return arr[low];
mid = (low + high) / 2;
if (arr[low] > arr[mid])
{
high = mid;
continue;
}
if (arr[mid] > arr[high])
{
low = mid;
continue;
}
while (low < mid)
{
if (arr[low] == arr[mid])
low++;
else if (arr[low] < arr[mid])
return arr[low];
else
{
high = mid;
break;
}
}
}
return min(arr[low], arr[high]);
}
//在有序旋转数组中找到一个数
bool isContains(int* arr, int len, int num)
{
int low = 0;
int high = len - 1;
int mid = 0;
while (low <= high)
{
mid = (low + high) / 2;
if (arr[mid] == num)
return true;
if (arr[low] == arr[mid] && arr[mid] == arr[high])
{
while (low != mid && arr[low] == arr[mid])
low++;
if (low == mid)
{
low = mid + 1;
continue;
}
}
if (arr[low] != arr[mid])
{
if (arr[mid] > arr[low])
{
if (num >= arr[low] && num < arr[mid])
high = mid - 1;
else
low = mid + 1;
}
else
{
if (num > arr[mid] && num <= arr[high])
low = mid + 1;
else
high = mid - 1;
}
}
else
{
if (arr[mid] < arr[high])
{
if (num > arr[mid] && num <= arr[high])
low = mid + 1;
else
high = mid - 1;
}
else
{
if (num >= arr[low] && num < arr[mid])
high = mid - 1;
else
low = mid + 1;
} //分析没有看太懂,还是不太清楚为什么多了这么几次
}
}
return false;
}
int main()
{
int len, num;
cin >> len >> num;
int* input = new int[len];
for (int i = 0; i < len; i++)
cin >> input[i];
int minVal = findMinValue(input, len);
bool res = isContains(input, len, num);
cout << minVal << endl;
if (res)
cout << "contains!" << endl;
else
cout << "not contain!" << endl;
getchar();
return 0;
}