给你一个数字数组 arr
如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false
示例 1:
输入:arr = [3,5,1]
输出:true
解释:对数组重新排序得到 [1,3,5] 或者 [5,3,1]
任意相邻两项的差分别为 2 或 -2 ,可以形成等差数列。
示例 2:
输入:arr = [1,2,4]
输出:false
解释:无法通过重新排序得到等差数列。
思路1:数组排序+逐项验证
最直观的思路就是,先把数组排序
然后一次遍历挨个判断两两之间的间距是否相等
如果相等,则为等差,否则不符合条件
int
cmpfun(void const* a, void const* b) {
return ((*(int*)a) - (*(int*)b));
}
bool canMakeArithmeticProgression(int* arr, int arrSize) {
if (2 == arrSize)return true;
qsort(arr, arrSize, sizeof(int), cmpfun); //快排
int gap = arr[1] - arr[0]; //记录两个数之间的差值
for (size_t i = 2; i < arrSize; i++) {
//逐项判断
if (arr[i] - arr[i - 1] != gap)
return false;
} return true;
}
女少口啊
思路2:验证等差求和公式
我们易知等差数列的求和公式为 (首项+尾项)x项数÷2
而首项和尾项之和自然就是最小项和最大项之和(显而易见)
所以,我们其实不需要对数组进行排序
我们只需要一次遍历数组,得到:最小项、最大项、总和
就可以根据上述求和公式验证是否为等差数列
bool canMakeArithmeticProgression(int* arr, int arrSize) {
double sum = 0.0;
int max = -99999999, min = +99999999;
for (size_t i = 0; i < arrSize; sum += arr[i++]) {
if (arr[i] > max)max = arr[i];
if (arr[i] < min)min = arr[i];
} return ((min + max) * arrSize / 2.0 == sum);
}
.
.
.
给你两个数组,arr1 和 arr2,
arr2 中的元素各不相同
arr2 中的每个元素都出现在 arr1 中
对 arr1 中的元素进行排序,
使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。
未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。
示例:
输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]
提示:
arr1.length, arr2.length <= 1000
0 <= arr1[i], arr2[i] <= 1000
arr2 中的元素 arr2[i] 各不相同
arr2 中的每个元素 arr2[i] 都出现在 arr1 中
思路:桶排序&哈希
这道题的思路源自网友。
首先需要知道桶排序这个东西,如果不知道的话,移步这个网站了解一下:
点击链接进行跳转: 桶排序快速扫盲
对桶排序有了个大概了解之后,这道题大概就有了思路了。
而且,观察题目所给的提示,也容易受到启发从而想到桶排序
具体思路是:
新建一个bucket数组,然后仿造桶排序,
以arr1的元素作为下标,对bucket中相应元素进行递增(有点类似于哈希)
紧接着对arr2进行遍历,
以arr2的元素作为下标,把bucket中符合条件的元素(即在arr1中出现过的元素)的下标取出来赋值到arr1
注意,在我们把arr1的元素“安排”进bucket之后,arr1已经是废物一个了
最后我们再把bucket中剩下的元素(也就是只在arr1中出现的元素)按照桶排序输出到arr1的末尾
Done!
int*
relativeSortArray(int* arr1, int arr1Size,
int* arr2, int arr2Size,
int* returnSize) {
*returnSize = arr1Size;
int bucket[1001] = {
0 }; //定义一个桶
for (size_t i = 0; i < arr1Size; i++) {
bucket[arr1[i]]++; //用bucket来记录arr1出现的元素
}
int loc = 0; //定义一个变量用来重新存储arr1的元素
for (size_t i = 0; i < arr2Size; i++) {
//注意这里要用while而不是if
while (bucket[arr2[i]]) {
//因为一个数字可能重复出现多次
arr1[loc++] = arr2[i]; //把arr2存在的值写入arr1
bucket[arr2[i]]--; //桶计数值减一
}
}
for (size_t i = 0; i < 1001; i++) {
//遍历桶把剩下的元素输出
while (bucket[i]) {
//符合条件的是只在arr1中出现过的元素
arr1[loc++] = i;
bucket[i]--;
}
} return arr1;
}
.
.
.
给你一个整数数组 salary ,数组里每个数都是 唯一 的,
其中 salary[i] 是第 i 个员工的工资。
请你返回去掉最低工资和最高工资以后,剩下员工工资的平均值。
示例 1:
输入:salary = [4000,3000,1000,2000]
输出:2500.00000
解释:最低工资和最高工资分别是1000 和 4000 。
去掉最低工资和最高工资以后的平均工资是 (2000+3000)/2= 2500示例 2:
输入:salary = [1000,2000,3000]
输出:2000.00000
解释:最低工资和最高工资分别是 1000和 3000 。
去掉最低工资和最高工资以后的平均工资是 (2000)/1= 2000
思路:不要排序!
这道题为什么会有人想到要去排序?!
直接一次遍历,求最大值、最小值、总和,然后返回需要的值不就行了?
double average(int* salary, int salarySize) {
double sum = 0.0;
int min = 1000000, max = 1000;
for (int i = 0; i < salarySize; sum += salary[i++]) {
if (salary[i] > max)max = salary[i];
if (salary[i] < min)min = salary[i];
} return (sum - max - min) / (salarySize - 2);
}
.
.
.
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:
输入: s = “rat”, t = “car”
输出: false
说明:
你可以假设字符串只包含小写字母。
思路1:哈希
这个应该是最容易想到的思路了,把每个字符映射到哈希表里面计数,
然后判断两个哈希表是否相等,不相等就false,全相等就true
bool isAnagram(char* s, char* t) {
int hashs[26] = {
0 }, hasht[26] = {
0 };
for (int i = 0; s[i]; hashs[s[i++] - 'a']++);
for (int i = 0; t[i]; hasht[t[i++] - 'a']++);
for (int i = 0; i < 26; i++) {
if (hashs[i] != hasht[i])
return false;
} return true;
}
思路2:位运算异或——我估计就我这奇葩想出来这种方法了
因为我们要判断两个字符串包含的元素是否相同,
于是可能会想到说,通过位运算的异或操作来排除相同的,
如果两个字符串元素全等,那么异或之后应该为0
(参考题268、题389)
于是有了以下代码:
bool isAnagram(char* s, char* t) {
char ret = 0;
int sum1 = 0, sum2 = 0;
for (int i = 0; s[i]; ret ^= s[i++]);
for (int i = 0; t[i]; ret ^= t[i++]);
return !ret;
}
但是这段代码只通过了力扣34个用例中的30个,卡在“aa”、“bb”这一对用例
所以我们发现如果两个字符是在本字符串中相消的,就有问题
于是我们就想着说,我们在这个基础上再顺带求一求字符串的和,
然后结尾再判断两个字符串各自之和是否相等
于是有了以下代码:
bool isAnagram(char* s, char* t) {
char ret = 0;
int sum1 = 0, sum2 = 0;
for (int i = 0; s[i]; sum1 += s[i], ret ^= s[i++]);
for (int i = 0; t[i]; sum2 += t[i], ret ^= t[i++]);
return (!ret) && (sum1 == sum2);
}
这段代码过了33/34个测试用例,卡在"xaaddy"、"xbbccy"这一对用例
所以还是有点遗憾,本来挺新颖的思路的…
.
.
.
给你一个整数数组 arr 。
请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
如果存在多个数字二进制中 1 的数目相同,
则必须将它们按照数值大小升序排列。
请你返回排序后的数组。
示例 1:
输入:arr = [0,1,2,3,4,5,6,7,8]
输出:[0,1,2,4,8,3,5,6,7]
解释:[0]是唯一一个有 0 个 1 的数。
[1,2,4,8] 都有 1 个 1 。
[3,5,6] 有 2 个 1 。
[7] 有 3 个 1 。
按照 1 的个数排序得到的结果数组为 [0,1,2,4,8,3,5,6,7]
示例 2:
输入:arr = [1024,512,256,128,64,32,16,8,4,2,1]
输出:[1,2,4,8,16,32,64,128,256,512,1024]
解释:数组中所有整数二进制下都只有 1 个 1,
所以你需要按照数值大小将它们排序
思路:快排,自己写比较函数
这个是网友的思路。
就,直接快排呗,反正题目要求是要排序,
只不过我们这里排序不单纯只是比较数字大小,
而是根据1的数量来作为排序依据,所以我们自己重新写cmpfun
int hammingWeight(uint32_t n) {
int cnt = 0;
while (n) {
if (n & 1)cnt++;
n >>= 1;
} return cnt;
}
int cmpfun(void const* a, void const* b) {
int ai = *(int*)a;
int bi = *(int*)b;
int cnta = hammingWeight(ai);
int cntb = hammingWeight(bi);
return (cnta == cntb) ? ai - bi : cnta - cntb;
//注意这里不是单纯的return cnta-cntb或者ai-bi
//而是要考虑如果位数相同则按照大小来,否则按照位数来
}
int* sortByBits(int* arr, int arrSize, int* returnSize) {
qsort(arr, arrSize, sizeof(int), cmpfun);
*returnSize = arrSize;
return arr;
}
.
.
.
给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。
对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;
当 A[i] 为偶数时, i 也是偶数。
你可以返回任何满足上述条件的数组作为答案。
示例:
输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。
思路1:开辟一个新的数组空间,遍历数组进行筛选
新建一个等大的数组,然后对原数组进行遍历,
遇到奇数就放到奇数位,遇到偶数就放到偶数位,然后下标移位2
int* sortArrayByParityII(int* A, int ASize, int* returnSize) {
*returnSize = ASize;
int even = 0, odd = 1;
int* retArr = (int*)malloc(sizeof(int) * ASize);
for (int i = 0; i < ASize; i++) {
if (A[i] % 2 == 0) {
retArr[even] = A[i];
even += 2;
} else {
retArr[odd] = A[i];
odd += 2;
}
} return retArr;
}
思路2:原地双指针转换
大家应该都会往这个方向想,但是具体实现可能不知道要咋操作
原地双指针的好处是不需要额外开辟空间,很棒
对于本题,奇偶对半,
只要处理好奇数,偶数就自然而然肯定“被处理好了”
同理,只要处理好偶数,奇数也就不用担心了
这里我们只处理偶数位,即A[0]、A[2]、A[4]…
两个下标,分别指向奇数位和偶数位(起始分别为1和0)
遍历数组,每次判断偶数位的数字是否为偶数
如果不是,则:在奇数位找到第一个不为奇数的偶数,二者交换
然后继续,直到遍历完数组
int* sortArrayByParityII(int* A, int ASize, int* returnSize) {
*returnSize = ASize;
int even = 0, odd = 1;
for (; even < ASize; even += 2) {
if (A[even] % 2 != 0) {
//偶数位为奇数
while (A[odd] % 2 == 1)
odd += 2; //在奇数位找偶数
//交换两个数
int temp;
temp = A[even];
A[even] = A[odd];
A[odd] = temp;
}
} return A;
}
.
.
.
给定两个数组,编写一个函数来计算它们的交集
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
思路1:排序+双指针
先对两个数组分别进行升序排序
然后双指针分别各自指向两个数组
判断两个指针指向的元素是否相等
如果不等,则“指向较小元素的指针”向后移位
如果相等,将结果存储到一个数组,同时两个指针同时向后移位
循环重复上述过程,直到其中某个数组遍历完成
int
cmpfun(void const* a, void const* b) {
return (*(int*)a > * (int*)b) ? 1 : 0;
} //注意这里不能直接返回a-b,因为测试用例其中有一例给了临界值
//如果临界值再减可能就要溢出了,所以这里直接判断大小,返回1或0
int* intersect(int* nums1, int nums1Size,
int* nums2, int nums2Size, int* returnSize) {
qsort(nums1, nums1Size, sizeof(int), cmpfun);
qsort(nums2, nums2Size, sizeof(int), cmpfun);
int locret = 0;
int* retArr = (int*)calloc((nums1Size > nums2Size ? nums2Size : nums1Size), sizeof(int)); //申请一个长度等于较小数组的新数组用于返回
for (int loc1 = 0, loc2 = 0; loc1 < nums1Size && loc2 < nums2Size; ) {
if (nums1[loc1] < nums2[loc2]) {
loc1++;
} else if (nums1[loc1] > nums2[loc2]) {
loc2++;
} else if (nums1[loc1++] == nums2[loc2++]) {
//同时移位
retArr[locret++] = nums1[loc1 - 1]; //存入相同值
}
} *returnSize = locret;
return retArr;
}
思路2:哈希
这道题蛮容易想到哈希映射的,但是由于题目没有明确给出元素大小范围和元素个数范围,C语言不方便哈希…代码就没敲了
.
.
.
给你一个字符串 s 和一个 长度相同 的整数数组 indices
请你重新排列字符串 s ,其中第 i 个字符需要移动到 indices[i] 指示的位置
返回重新排列后的字符串。
示例 1:
输入:s = “aiohn”, indices = [3,1,4,2,0]
输出:“nihao”
示例 2:
输入:s = “aaiougrt”, indices = [4,0,2,6,7,3,1,5]
输出:“arigatou”
示例 3:
输入:s = “art”, indices = [1,0,2]
输出:“rat”
思路:新开辟数组空间+按indices重新写入数据
如题,开辟一个等大的空间,然后依次读入indices的新loc,
再在新数组的相应位置写入数据
char* restoreString(char* s, int* indices, int indicesSize) {
char* retArr = (char*)calloc(indicesSize + 1, sizeof(char));
for (int i = 0; i < indicesSize; i++) {
retArr[indices[i]] = s[i];
} return retArr;
}