四数相加2
- 前提
- 不用考虑每个数组使用重复的元素
- 要点
- A+B+C+D = (A+B) + (C+D) -> -(A+B) = C+D,相当于查找CD之和中有无等于AB之和的负数。可以使用哈希查找
- 数据范围大,而且需要记录重复的AB和数量,考虑使用unordered_map
- key存储AB和,value存储重复的AB和数量
typedef struct {
int key;
int value;
UT_hash_handle hh;
}map;
map *hashMap = NULL;
map* hashMapFind(int key){
map* tmp = NULL;
HASH_FIND_INT(hashMap, &key, tmp);
return tmp;
}
void hashMapAdd(int key, int value){
if (hashMapFind(key) == NULL){
map* tmp = malloc(sizeof(map));
tmp -> key = key;
HASH_ADD_INT(hashMap, key, tmp);
tmp -> value = value;
}
}
void hashMapPrint(){
map* cur = NULL;
for (cur = hashMap; cur != NULL; cur = cur -> hh.next){
printf("key:%d, value:%d\n", cur -> key, cur -> value);
}
}
void hashMapCleanUp(){
map *cur, *tmp;
HASH_ITER(hh, hashMap, cur, tmp){
HASH_DEL(hashMap, cur);
free(cur);
}
}
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
hashMap = NULL;
map *hashMapRec = NULL;
int cnt = 0;
for (int i = 0; i < nums1Size; i++){
for (int j = 0; j < nums2Size; j++){
int sum1 = nums1[i] + nums2[j];
hashMapRec = hashMapFind(sum1);
if (hashMapRec == NULL){
hashMapAdd(sum1, 1);
}
else {
hashMapRec -> value++;
}
}
}
hashMapPrint();
for (int i = 0; i < nums3Size; i++){
for (int j = 0; j < nums4Size; j++){
int sum2 = nums3[i] + nums4[j];
hashMapRec = hashMapFind(-sum2);
if (hashMapRec != NULL){
cnt = cnt + hashMapRec -> value;
}
}
}
hashMapCleanUp();
return cnt;
}
赎金信
- 前提
ransomNote
和magazine
由小写英文字母组成magazine
中的每个字符只能在ransomNote
中使用一次
- 要点
- 可以使用数组哈希查找
bool canConstruct(char* ransomNote, char* magazine) {
int arrayRec[26] = {0};
int sizeR = strlen(ransomNote);
int sizeM = strlen(magazine);
if (sizeM < sizeR){
return false;
}
for (int i = 0; i < sizeM; i++){
arrayRec[magazine[i] - 'a']++;
}
for (int i = 0; i < sizeR; i++){
if (arrayRec[ransomNote[i] - 'a'] > 0){
arrayRec[ransomNote[i] - 'a']--;
}
else {
return false;
}
}
return true;
}
三数之和
-
前提
i != j
、i != k
且j != k
- 答案中不可以包含重复的三元组
-
要点
-
先将数组排序
-
双指针法:在
for
循环里(i
从0开始)使用快慢指针left
、right
-
使
a=nums[i]
,b=nums[left]
,c=nums[right]
,求a+b+c=0
-
在第
i
层循环,while(left < right)
如何移动指针一次移动一格
- 剪枝
- 当
(a+b) +c > 0
时,左移right
- 当
(a+b) +c < 0
时,右移left
- 当
- 当
(a+b) +c = 0
时,更新left
、right
- 剪枝
-
a
,b
,c
如何去重- 当
nums[i] = nums[i-1]
时,会重复上一轮的操作,i
向后移动 - 当
nums[left+1] = nums[left]
时,会重复上轮的操作,left++
- 当
nums[right-1] = nums[right]
时,会重复上一轮操作,right--
- 当
-
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
#define MAX_SIZE 18000
/* qsort辅助cmp函数 */
int cmp(const void *a, const void *b){
return *(int*)a - *(int*)b;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
int **returnArray = malloc(sizeof(int*) * MAX_SIZE);
int cnt = 0;
if (numsSize < 3){
*returnSize = 0;
return returnArray;
}
qsort(nums, numsSize, sizeof(int), cmp);
for (int i = 0; i < numsSize - 2; i++){
if (nums[i] > 0){
break;
}
//i去重
if (i > 0 && nums[i] == nums[i-1]){
continue;
}
int left = i + 1;
int right = numsSize - 1;
while (left < right){
int sum = nums[i] + nums[left] + nums[right];
if (sum < 0){
left ++;
}
else if (sum > 0){
right --;
}
else {
returnArray[cnt] = malloc(sizeof(int)*3);
returnArray[cnt][0] = nums[i];
returnArray[cnt][1] = nums[left];
returnArray[cnt][2] = nums[right];
cnt++;
//left、right去重
while (left < right && nums[left] == nums[left+1]){
left++;
}
while (left < right && nums[right] == nums[right-1]){
right--;
}
//更新left、right
left++;
right--;
}
}
}
*returnSize = cnt;
*returnColumnSizes = malloc(sizeof(int)*cnt);
for (int i = 0; i < cnt; i++){
(*returnColumnSizes)[i] = 3;
}
return returnArray;
}
四数之和
- 前提
a
、b
、c
和d
互不相同- 答案中不可以包含重复的四元组
- 要点
- 解题思路参考三数之和
- 去重部分相同,剪枝部分不同:
target
可能是负数,此时不能用nums[k] > target
剪枝,例如target=-4, nums=[-3,-1,0,1]
- 使用
nums[k]*4 > target
- 加法的中间过程有可能数据溢出,将加数强转为
long int
解决
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
#define MAX_SIZE 18000
int cmp(const void *a, const void *b){
return *(int*)a - *(int*)b;
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {
int **returnArray = malloc(sizeof(int*) * MAX_SIZE);
int cnt = 0;
if (numsSize < 4){
*returnSize = 0;
return returnArray;
}
qsort(nums, numsSize, sizeof(int), cmp);
for (int k = 0; k < numsSize-3; k++){
if (nums[k] > 0 && nums[k] > target){
break;
}
if (k > 0 && nums[k] == nums[k-1]){
continue;
}
for (int i = k+1; i < numsSize-2; i++){
if (nums[i] > 0 && ((long int)nums[k] + (long int)nums[i]) > target){
break;
}
if (i > k+1 && nums[i] == nums[i-1]){
continue;
}
int left = i+1;
int right = numsSize-1;
while (left < right){
long int sum = (long int)nums[k] + (long int)nums[i] + (long int)nums[left] + (long int)nums[right];
if (sum < target){
left++;
}
else if (sum > target){
right--;
}
else {
returnArray[cnt] = malloc(sizeof(int) * 4);
returnArray[cnt][0] = nums[k];
returnArray[cnt][1] = nums[i];
returnArray[cnt][2] = nums[left];
returnArray[cnt][3] = nums[right];
cnt++;
while (left < right && nums[left+1] == nums[left]){
left++;
}
while (left < right && nums[right-1] == nums[right]){
right--;
}
left++;
right--;
}
}
}
}
*returnSize = cnt;
*returnColumnSizes = malloc(sizeof(int)*cnt);
for (int i = 0; i < cnt; i++){
(*returnColumnSizes)[i] = 4;
}
return returnArray;
}
总结
- 解题思路
- 要不要用哈希表
- 选什么哈希结构
- 哈希结构存什么,怎么映射,怎么用
- 有时用双指针法更简便
- 关注去重和剪枝