【代码随想录】【算法训练营】【第7天】 [454]四数之和Ⅱ [383]赎金信 [15]三数之和 [18]四数之和

前言

思路及算法思维,指路 代码随想录
题目来自 LeetCode

day 7,周二,继续继续~

题目详情

[454] 四数之和Ⅱ

题目描述

454 四数之和Ⅱ
454 四数之和Ⅱ

解题思路

前提:四个证书组 + 所求符合条件的元组个数
思路:哈希,就四数之和,可以简化为(A+B)+C+D == 0的形式(三数之和)。
重点:构造哈希结构,不仅需要保存key,还需要保存key的数量。

代码实现

C语言
使用UT_hash库接口
typedef struct hashTable{
    int val;
    int cnt;
    UT_hash_handle hh;
};

void TwoSum(int* numsA, int numsASize, int* numsB, int numsBSize, struct hashTable **hash){
    for (int i = 0; i < numsASize; i++)
    {
        for (int j = 0; j < numsBSize; j++)
        {
            int sumAB = numsA[i] + numsB[j];
            struct hashTable *tmp;
            HASH_FIND_INT(*hash, &sumAB, tmp);
            if (tmp == NULL)
            {
                struct hashTable *tmp = (struct hashTable *)malloc(sizeof(struct hashTable));
                tmp->val = sumAB;
                tmp->cnt = 1;
                HASH_ADD_INT(*hash, val, tmp);
            }
            else
            {
                tmp->cnt++;
            }
        }
    }
    return ;
}

int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
    struct hashTable *hashTable = NULL;
    TwoSum(nums1, nums1Size, nums2, nums2Size, &hashTable);
    int count = 0;
    for (int i = 0; i < nums3Size; i++)
    {
        for (int j = 0; j < nums4Size; j++)
        {
            int val = 0 - nums3[i] - nums4[j];
            struct hashTable *tmp;
            HASH_FIND_INT(hashTable, &val, tmp);
            if (tmp != NULL)
            {
                count += tmp->cnt;
            }
            else
            {
            }
        }
    }
    return count;
}
自己实现哈希接口
#define HASH_TABLE_LEN 256

typedef struct Node {
    int val;
    int cnt;
    struct Node *next;
}NODE, *HashTable;

void initHashTable(HashTable *hash)
{
    for (int i = 0; i < HASH_TABLE_LEN; i++)
    {
        struct Node *head = (struct Node *)malloc(sizeof(struct Node));
        memset(head, 0, sizeof(struct Node));
        hash[i] = head;
    }

    return ;
}

void insertHashTable(HashTable *hash, int val)
{
    int index = val < 0 ? (-val) % HASH_TABLE_LEN : val % HASH_TABLE_LEN;
    struct Node *last = hash[index]; //虚拟头节点
    while (last->next)
    {
        if (last->next->val == val)
        {
            last->next->cnt++;
            return;
        }
        last = last->next;
    }
    struct Node *new = (struct Node *)malloc(sizeof(struct Node));
    new->val = val;
    new->cnt = 1;
    new->next = NULL;
    last->next = new;

    return ;
}

int foundHashTable(HashTable *hash, int val)
{
    int index = val < 0 ? (-val) % HASH_TABLE_LEN : val % HASH_TABLE_LEN;
    struct Node *cur = hash[index];
    while (cur->next)
    {
        if (cur->next->val == val)
        {
            return cur->next->cnt;
        }
        cur = cur->next;
    }

    return 0;
}

void freeHashTable(HashTable *hash)
{
    for (int i = 0; i < HASH_TABLE_LEN; i++)
    {
        struct Node *cur = hash[i];
        while (cur)
        {
            struct Node *next = cur->next;
            free(cur);
            cur = next;
        }
    }

    return ;
}

void TwoSum(int* numsA, int numsASize, int* numsB, int numsBSize, HashTable *hash){
    for (int i = 0; i < numsASize; i++)
    {
        for (int j = 0; j < numsBSize; j++)
        {
            int sumAB = numsA[i] + numsB[j];
            insertHashTable(hash, sumAB);
        }
    }
    return ;
}

int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
    HashTable hashTable[HASH_TABLE_LEN];
    initHashTable(hashTable);
    TwoSum(nums1, nums1Size, nums2, nums2Size, hashTable);
    int count = 0;
    for (int i = 0; i < nums3Size; i++)
    {
        for (int j = 0; j < nums4Size; j++)
        {
            count += foundHashTable(hashTable, (0 - nums3[i] - nums4[j]));
        }
    }
    //freeHashTable(hashTable);
    return count;
}

[383] 赎金信

题目描述

383 赎金信
383 赎金信

解题思路

前提:ransomNote中的字母是不是完全由magazine中字母组成
思路:统计magazine中字母出现的次数,看是否完全包含ramsomNote字母的次数。
重点:哈希结构,由于均有小写字母组成,使用数组实现即可。

代码实现

C语言
bool canConstruct(char* ransomNote, char* magazine) {
    int hash[26] = {0};
    if (strlen(magazine) < strlen(ransomNote))
    {
        return false;
    }
    for (int i = 0; i < strlen(magazine); i++)
    {
        hash[magazine[i] - 'a']++;
    }
    for (int j = 0; j < strlen(ransomNote); j++)
    {
        if (hash[ransomNote[j] - 'a'] > 0)
        {
            hash[ransomNote[j] - 'a']--;
        }
        else
        {
            return false;
        }
    }
    return true;
}

[15] 三数之和

题目描述

15 三数之和
15 三数之和

解题思路

前提:三元组不重复
思路:三元组不重复,必定要对nums数组去重,需要三个指针,left、middle、right,遍历left指针,在left指针固定的情况下,middle在(left, right)范围遍历,不断收缩middle、right指针,直至重合,遍历完成。
重点:去重操作的判断,当指针移动时,均需要判重过滤。

代码实现

C语言
/**
 * 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().
 */

int cmp(const void *p1, const void *p2)
{
    return (int)(*(int *)p1 > *(int *)p2);
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    if (numsSize < 3)
    {
        *returnSize = 0;
        return NULL;
    }
    // 排序,方便去重
    qsort(nums, numsSize, sizeof(int), cmp);
    *returnSize = 0;
    int mallocSize = numsSize;
    int **ret = (int **)malloc(sizeof(int *) * mallocSize);
    *returnColumnSizes = (int *)malloc(sizeof(int) * mallocSize);
	// 遍历left
    for (int left = 0; left < numsSize - 2; left++)
    {
    	// 初始化middle、right
        int middle = left + 1;
        int right = numsSize - 1;
        // 过滤重复left
        if ((left > 0) && (nums[left] == nums[left - 1]))
        {
            continue;
        }
        // 寻找符合条件的middle和right
        while (middle < right)
        {
            int sum = nums[left] + nums[middle] + nums[right];
            if (sum > 0)
            {
                right--;
                continue;
            }
            else if (sum < 0)
            {
                middle++;
                continue;
            }
            // 找到符合条件的middle和right
            // 返回空间不足时重新分配空间
            if (mallocSize <= *returnSize)
            {
                mallocSize = mallocSize * 2;
                ret = (int **)realloc(ret, sizeof(int *) * mallocSize);
                *returnColumnSizes = (int *)realloc(*returnColumnSizes, sizeof(int) * mallocSize);
            }
            ret[*returnSize] = (int *)malloc(sizeof(int) * 3);
            ret[*returnSize][0] = nums[left];
            ret[*returnSize][1] = nums[middle];
            ret[*returnSize][2] = nums[right];
            (*returnColumnSizes)[*returnSize] = 3;
            (*returnSize)++;
            //对已找到的middle和right移位去重
            int tmp = nums[middle];
            while ((middle < right) && (nums[middle] == tmp))
            {
                middle++;
            }
            tmp = nums[right];
            while ((middle < right) && (nums[right] == tmp))
            {
                right--;
            }
        }
    }
    return ret;
}

[18] 四数之和

题目描述

18 四数之和
18 四数之和

解题思路

前提:四元组不重复
思路:四元组不重复,必定要对nums数组去重,需要四个指针,loc1、loc2、loc3、loc4,遍历loc1和loc2指针,在loc1和loc2指针固定的情况下,loc3在(loc2, loc4)范围遍历,不断收缩loc3、4oc3指针,直至重合,遍历完成。
重点:去重操作的判断,当指针移动时,均需要判重过滤。

代码实现

C语言
/**
 * 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().
 */
int compare(const void *p1, const void *p2)
{
    return (*(int *)p1 > *(int *)p2);
}

int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {
    int mallocSize = numsSize;
    *returnSize = 0;

    //排除异常情况
    if (numsSize < 4)
    {
        return NULL;
    }
    
    // 排序,以便去重
    qsort(nums, numsSize, sizeof(int), compare);

    int **ret = (int **) malloc(sizeof(int *) * mallocSize);
    *returnColumnSizes = (int *)malloc(sizeof(int) * mallocSize);
    // 寻找四元组
    // 遍历loc1
    for (int loc1 = 0; loc1 < numsSize; loc1++)
    {
        // 去重
        if ((loc1 > 0) && (nums[loc1] == nums[loc1 - 1]))
        {
            continue;
        }
        // 遍历loc2
        for (int loc2 = (loc1 + 1); loc2 < numsSize; loc2++)
        {
            // 去重
            if((loc2 > (loc1 + 1)) && (nums[loc2] == nums[loc2 - 1]))
            {
                continue;
            }
            // 初始化loc3 和loc4 
            int loc3 = loc2 + 1;
            int loc4 = numsSize - 1;
            // 寻找符合条件的loc3和loc4 
            while (loc3 < loc4)
            {
                long sum = (long)nums[loc1] + (long)nums[loc2] + (long)nums[loc3] + (long)nums[loc4];
                if (sum > target)
                {
                    loc4--;
                    continue;
                }
                else if (sum < target)
                {
                    loc3++;
                    continue;
                }
                // 找到符合条件的loc3和loc4 
                // 返回空间不足时重新分配空间
                if (mallocSize <= *returnSize)
                {
                    mallocSize *= 2;
                    ret = (int **)realloc(ret, sizeof(int *) * mallocSize);
                    *returnColumnSizes = (int *)realloc(*returnColumnSizes, sizeof(int) * mallocSize);
                }
                // 赋值四元组
                ret[*returnSize] = (int *)malloc(sizeof(int) * 4);
                ret[*returnSize][0] = nums[loc1];
                ret[*returnSize][1] = nums[loc2];
                ret[*returnSize][2] = nums[loc3];
                ret[*returnSize][3] = nums[loc4];
                (*returnColumnSizes)[*returnSize] = 4;
                (*returnSize)++;
                // 对已找到的loc3和loc4去重
                int tmp = nums[loc3];
                while ((loc3 < loc4) && nums[loc3] == tmp)
                {
                    loc3++;
                }
                tmp = nums[loc4];
                while ((loc3 < loc4) && nums[loc4] == tmp)
                {
                    loc4--;
                }
            }
        }
    }
    return ret;
}

今日收获

  1. 哈希的实现:数组、自实现hash库、UT_hash库的使用。
  2. 四数之和、四数之和Ⅱ的区别;三数之和、四数之和对于去重的判断:要跟之前遍历过得元素判重,以便遗漏符合条件的组合。
  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值