代码随想录第五十八期day07

代码随想录第五十八期day07

题目1:454. 四数相加 II
题目描述:给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

示例 1:

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:

  1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
  2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
    示例 2:

输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1

提示:

n == nums1.length
n == nums2.length
n == nums3.length
n == nums4.length
1 <= n <= 200
-2^ 28 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 2^28
解析:本题乍一看很简单,但是真正要写会发现很困难,题意就是从给到的四个数组中,一个数组取一个元素,再对这四个元素求和,使得他们和为0,即得一种,题目要返回的是从这四个数组里面一共能找到多少个这样的元组,使得他们和为0,对于本题我优先想到4层for循环,那么他的时间复杂度为O(N^4)这个复杂度相当的大,可想而知,超时了,代码如下:

int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size) {
    int count=0;
    for(int i = 0;i<nums1Size;i++){
        for(int j = 0;j<nums1Size;j++){
            for(int k = 0;k<nums1Size;k++){
                for(int r = 0;r<nums4Size;r++){
                    if(nums1[i]+nums2[j]+nums3[k]+nums4[r] == 0)count++;
                }
            }
        }
    }
    return count;
}

然后实在没思路,最后去看了Carl哥讲解,思路就是降o(n^ 4)为o(n^2)。归并排序的思想,两两求和来实现降为o(n ^ 2);由于不知道两个数组中元素求和后有多少个元素,所以用了链表来保存。本题用了一个hashmap,hashmap里面定义的key用来存和,value用来存出现了几次,这样就能在后面方便统计。解题步骤:
本题解题步骤:

1首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
2遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
3定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
4再遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
5最后返回统计值 count 就可以了。
代码如下:

// 哈希表大小
const int HASH_SIZE = 101;

typedef struct node {
    int val;
    int count;
    struct node *next;
} node, *HashMap;

// 哈希表插入
void hash_insert(HashMap hashmap[], int val) {
    int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE, count = 0;
    node *p = hashmap[idx];
    while (p->next != NULL) {
        p = p->next;
        if (p->val == val) {
            (p->count)++;
            return;
        }
    }
    node *new = malloc(sizeof(node));
    new->val = val;
    new->count = 1;
    new->next = NULL;
    p->next = new;
    return;
}

// 哈希表查找
int hash_search(HashMap hashmap[], int val) {
    int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE;
    node *p = hashmap[idx];
    while (p->next != NULL) {
        p = p->next;
        if (p->val == val) return p->count;
    }
    return 0;
}

int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
    // 初始化哈希表
    HashMap hashmap[HASH_SIZE];
    for (int i = 0; i < HASH_SIZE; i++) {
        hashmap[i] = malloc(sizeof(node));
        hashmap[i]->next = NULL;
    }
    
    // 统计两个数组元素之和的负值和出现的次数,放到哈希表中
    int count = 0, num;
    for (int i = 0; i < nums1Size; i++) {
        for(int j = 0; j < nums2Size; j++) {
            num = - nums1[i] - nums2[j];
            hash_insert(hashmap, num);
        }
    }
    
    // 统计另外两个数组元素之和,查找哈希表中对应元素的出现次数,加入总次数
    for (int i = 0; i < nums3Size; i++) {
        for(int j = 0; j < nums4Size; j++) {
            num = nums3[i] + nums4[j];
            count += hash_search(hashmap, num);
        }
    }
    return count;
}

题目2:383. 赎金信
题目:给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

示例 1:

输入:ransomNote = “a”, magazine = “b”
输出:false
示例 2:

输入:ransomNote = “aa”, magazine = “ab”
输出:false
示例 3:

输入:ransomNote = “aa”, magazine = “aab”
输出:true

提示:

1 <= ransomNote.length, magazine.length <= 105
ransomNote 和 magazine 由小写英文字母组成

解析:本题比较简单,直接hash映射到数组下标就能完成,和之前的有道题目很像,242. 有效的字母异位词思路一致,都是问能不能由另一个来组成,代码如下:

bool canConstruct(char* ransomNote, char* magazine) {
    //hash映射
    int Hash_1[26]={0};
    int Hash_2[26]={0};
    for(int i = 0;i<strlen(ransomNote);i++){
        Hash_1[((int)ransomNote[i])-97]++;
    }
    for(int i = 0;i<strlen(magazine);i++){
        Hash_2[((int)magazine[i])-97]++;
    }
    for(int i = 0;i<26;i++){
        if(Hash_1[i] != 0){
            if(Hash_1[i] > Hash_2[i])return false;
        }
    }
    return true;
}

题目三:15. 三数之和
题目:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

3 <= nums.length <= 3000
-105 <= nums[i] <= 105
解析:本题中重点在于要找到的是不重复的三元组,使得他们和为0,然后输出这些三元组,对于这个问题,我们可以用双指针法来解决,即先给原来的数据排序,再用一个指针来遍历,其余两个指针left,right来查抄所符合条件的三元组,和大了就right–,和小了就left++;这样当条件为left>right时候就可以结束查找,在走遍历的指针,直到查找完,就能实现三数之和,cpp代码如下:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
    int n = nums.size();
    if (n < 3) return result;

    sort(nums.begin(), nums.end());

    for (int i = 0; i < n - 2; i++) {
        if (i > 0 && nums[i] == nums[i - 1]) continue;

        int left = i + 1, right = n - 1;
        int target = -nums[i];

        while (left < right) {
            int sum = nums[left] + nums[right];

            if (sum == target) {
                result.push_back({nums[i], nums[left], nums[right]});

                while (left < right && nums[left] == nums[left + 1]) left++;
                while (left < right && nums[right] == nums[right - 1]) right--;

                left++;
                right--;
            } else if (sum < target) {
                left++;
            } else {
                right--;
            }
        }
    }

    return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值