目录
题目一:970. 强整数
问题描述:
给定三个整数 x 、 y 和 bound ,返回 值小于或等于 bound 的所有 强整数 组成的列表 。
如果某一整数可以表示为 xi + yj ,其中整数 i >= 0 且 j >= 0,那么我们认为该整数是一个 强整数 。
你可以按 任何顺序 返回答案。在你的回答中,每个值 最多 出现一次。
0 <= bound <= 10^6
问题思路:
- 因为题目所给的bound值小于10的六次方,而2的20次方是1048756,并且x,y的值都大于等于2,因此建立一个res1[ ]与res2[ ]存储x与y不同次方的结果 。(两个数组的大小都等于21,代表从x^0,x^1....x^21与y^0,y^1,y^2...y^21的值)
- 建立两个for循环,判断result = res[i]与res[j]相加是否小于bound,是则哈希表hash[result]的值为1
- i=0到哈希表最后一个元素,值为1的将下标放到ret数组
代码:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* powerfulIntegers(int x, int y, int bound, int* returnSize){
long res1[21];
long res2[21];
int i, j;
for(i=0;i < 21;i++) //将x的不同次方放入res1数组
{
res1[i] = pow(x, i);
}
for(i=0; i< 21;i++) //将y的不同次方放入res1数组
{
res2[i] = pow(y, i);
}
int hash[2000000];
int result = 0;
memset(hash, 0, hash);
for(i=0; i<21; i++) //将符合res1[i]+res2[j] <=boud的放入哈希表,令hash[result] = 1;
for(j=0; j<21; j++)
{
result = res1[i] + res2[j];
if(result > bound)
{
break;
}
if(result <= bound)
hash[result] = 1;
}
i, j=0;
*returnSize = 0;
while(i<= bound && hash[i] != 0) //统计符合条件值的个数
{
(*returnSize)++;
}
int *ans = (int *)malloc(sizeof(int) * ( (*returnSize)+1) ); //动态创建数组
int temp = 0;
for(i=0; i<bound+1; i++) //hash[i]的值不为0的 i放入ans数组
if(i<= bound && hash[i] != 0)
{
ans[temp] = i;
temp++;
}
}
return ans;
}
题目二:914. 卡牌分组
问题描述:
给定一副牌,每张牌上都写着一个整数。
此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:
每组都有 X 张牌。
组内所有的牌上都写着相同的整数。
仅当你可选的 X >= 2 时返回 true。
问题思路:
一开始看题目示例,以为每个数字出现的次数是一样的,于是想着先把数组中每个元素出现的次数用哈希表记录下来,如果有一个元素出现次数不同,则返回false,提交之后直接解答错误。仔细看了一下,[1,1,1,1,1,1,2,2]可以分成[1,1],[1,1],[1,1],[2,2]四组,只要每组牌的个数大于等于K即可.
因此找他们之间的规律,发现每个数字出现的个数都与K有最大公因数(>1),这个条件转换成每个数字出现的个数之间都有最大公因数(>1),如果是则true,否则为false。
代码:
int gongyueshu(int a, int b)
{
int c;
while(b)
{
c = a % b;
a = b;
b = c;
}
return a;
}
bool hasGroupsSizeX(int* deck, int deckSize){
int hash[100011];
int temp;
memset(hash,0,sizeof(int) * 100011);
int i = 0;
for(i=0; i<deckSize; i++) //将每个数字出现的次数计入哈希表
{
++hash[deck[i]];
}
int gcd = -1;
for(i=0; i<100011; i++) //求每个次数之间的最大公约数
{
if(hash[i] == 1)
return false;
if(hash[i] != 0 )
{
if(gcd == -1)
{
gcd = hash[i];
}
else
{
gcd = gongyueshu(gcd,hash[i]);
if(gcd == 1) //如果最大公约数为1则返回false
return false;
}
}
}
return true;
}
题目三:1497. 检查数组对是否可以被 k 整除
给你一个整数数组 arr 和一个整数 k ,其中数组长度是偶数,值为 n 。
现在需要把数组恰好分成 n / 2 对,以使每对数字的和都能够被 k 整除。
如果存在这样的分法,请返回 True ;否则,返回 False 。
问题思路:
这道题一开始简单的想当然记录每个数出现的次数,循环遍历hash[i],看是否出现hash[j]使两者之和相加为0,但是提交之后解答错误。原因是hash[i]中的i是可以随机与其他数匹配的,使之相加为k,这样就出现了非常多的匹配结果,用n重循环显然是不现实的(时间复杂度过高)。
所以正确的思路是对每个数出现的次数取模,并且hash[mode]的值即为出现的次数,判断hash[i]与hash[k-i]的次数是否一致,不一致则返回false,全部模扫描完毕之后,如果没有出现return false,则返回true。
代码:
bool canArrange(int* arr, int arrSize, int k){
int hash[1000010];
int mod;
memset(hash,0,sizeof(int) * 1000010);
for(int i=0; i<arrSize; i++)
{
mod = (arr[i] % k +k) % k; //PS:看了题解才知道这里的取模是防止array[i]取负数,并且取模之
后数的范围就变成1-k了
++hash[mod];
}
if(hash[0] % 2) // 如果余数为0的出现次数为奇数,则必有一个落单
return false;
for(int i=1; i<k; i++) //判断hash[i] 与hash[k-i]的个数是否相等
if(hash[i] != hash[k-i])
return false;
return true;
}
题目四: 面试题 17.05. 字母与数字
问题描述:
给定一个放有字母和数字的数组,找到最长的子数组,且包含的字母和数字的个数相同。
返回该子数组,若存在多个最长子数组,返回左端点下标值最小的子数组。若不存在这样的数组,返回一个空数组。
解题思路:
这道题感觉自己理解的不透彻,似懂非懂就是不懂,先把题目收藏,把大概思路列出来,之后再过一遍。
遍历数组,如果是字母则记为-1,是数字记为1,例【‘1’,‘A’,‘B’,‘2’】则转换为[“1”,“-1“”, ‘-1’,‘1”];用sum[i]计算它们的前缀和,这里注意,前缀和相同的两下标之间的字母和数字是相同的,即中间的前缀和为0.
建立哈希表,记录hash[sum[i]],此时值为第一次出现这个元素的sum数组下标。遍历i,
if ((i - hash[sum[i]]) > max) { 如果出现同前缀,记录开始和结束标志。
max = i - hash[sum[i]];
start = hash[sum[i]];+ 1;
end = i;
} //
如果sum[i] == arraySize(sum[i]如果没加arrSize,此处的条件则为==0),说明0-i这个范围内数字和字母的个数相等,此时start为0,end为i,长度为i+1
代码:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
char** findLongestSubarray(char** array, int arraySize, int* returnSize){
int i, j = 0;
int sum[100010];
if(array[0][0] <= 'Z' && array[0][0] >='A' || array[0][0] <= 'z' && array[0][0] >='a')
sum[0] = -1;
else
sum[0] = 1;
int q = 1;
for(i=1; i<arraySize; i++)
{
if(array[i][0] <= 'Z' && array[i][0] >='A' || array[i][0] <= 'z' && array[i][0] >='a')
{
sum[i] = sum[i] - 1;
q--;
}
else
{
sum[i] = sum[i] + 1;
q++;
}
}
for(i=0; i<q; i++)
sum[i] = sum[i] + arraySize; //这里是防止hash[sum[i]]的sum[i]<0
int start, max, end = -1;
int hash[100010];
memset(hash,-1,sizeof(int)*100010);
for(i=0; i<q; i++)
{
if(sum[i] == arraySize)
{
if(i+1 > max)
{
max = i + 1;
start = 0;
end = i;
}
}
continue;
if (hash[sum[i]] == -1) {
hash[sum[i]] = i;
} else {
if ( i - hash[sum[i]] > max) {
max = i - hash[sum[i]];
start = hash[sum[i]] + 1;
end = i;
}
}
}
if(start == -1 || end == -1)
{
*returnSize = 0;
return NULL;
}
*returnSize = end - start +1;
char** ret = (char**)malloc((*returnSize) * sizeof(char*));
for (int i = 0; i < *returnSize; i++) {
ret[i] = (char*)malloc(20);
strcpy(ret[i], array[start + i]);
}
return ret;
}