首页 > 其他分享 >代码随想录训练营day9|第454题.四数相加II,383. 赎金信,第15题. 三数之和,

代码随想录训练营day9|第454题.四数相加II,383. 赎金信,第15题. 三数之和,

时间:2023-03-10 23:56:22浏览次数:53  
标签:map 四数 15 nums ran 随想录 right 数组 left

第454题.四数相加II

题目链接:第454题.四数相加II
题目描述:给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。

输入:                                输出:  2

A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
解释:

两个元组如下:

(0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
(1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0

思路

本题是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于题目18. 四数之和,题目15.三数之和,还是简单了不少!
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也就是出现次数统计出来。

代码展示

//四数相加Ⅱ
与四数之和不一样
class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D){
    	unordered_map(int , int )map;
		for(a:A){//遍历前两个数组去统计a+b
		 for(b:B) {
		 	map[a+b]++;//用map去映射,并且value加一 
		 }    
		}
	// 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。 
		for (int c : C) {
            for (int d : D) {
            	target = 0 - (c+d);//这就是要查的目标值,因为加起来才为0 
                if (umap.find(0 - (c + d)) != umap.end()) {、、//在遍历过程中找到target 
                    count += map[target];//这里的value出现的次数就是符合条件按的键值数,key即对应的数值 
                }
				}
				}
		return count;		
	} }

383. 赎金信

题目链接:383. 赎金信
题目描述:给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。

你可以假设两个字符串均只含有小写字母。

canConstruct("a", "b") -> false
canConstruct("aa", "ab") -> false
canConstruct("aa", "aab") -> true

思路

直接暴力解法--两层for循环,不断去查找。代码如下:

暴力解法:
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
		for(i = 0; i < magazine.size(); i++){//bian li A
			for(j = 0; j < ransonNote.size(); j++){//bianliB
				if(ma[i] == ran[j]){//在遍历ran里找到和ma数组的相同的字符 
					ran.erase(ran.begin() + j);//删除掉相同的字符
					break; 
			}
		}
		}
		if(ran.size() = 0){//如果ran数组为空,那么ma的字符就直接组成ran 
			return true;
		}
		return false; 
	}
}

哈希解法

依然是数组在哈希法中的应用。
那么为什么用数组你???用数组干啥,都用map完事了,其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!

代码如下

//哈希法解赎金
题目所只有小写字母,那可以采用空间换取时间的哈希
策略, 用一个长度为26的数组还记录magazine里字母出现的次数 
再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine){
    	int record[26];
		if(ran.size( > mag.size())){//ran数组若大于mag数组,直接gg 
			return false;
		}	
		if(int i = 0; i < mag.seze(); i++ ){
			record[magazine[i]-'a'] ++;// 通过recode数据记录 magazine里各个字符出现次数
		} 
		for(int j = 0; j < ran.size(); j++){
			record[ransomNote[j]-'a']--;// 遍历ransomNote,在record里对应的字符个数做--操作
			if(record[ran[j] - 'a'] < 0){ 
				return false;// 如果小于零说明ransomNote里出现的字符,magazine没有
			}
		}
		return true;
	}
	}

15.三数之和

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

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]

思路

使用哈希法非常棘手,去重的过程不好处理,有很多小细节,如果在面试中很难想到位。
时间复杂度可以做到O(n^2),但还是比较费时的,因为不好做剪枝操作。
双指针法

拿这个nums数组来举例,首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。

依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i],b = nums[left],c = nums[right]。

接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。

如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。

时间复杂度:O(n^2)。

代码实现

//第15题. 三数之和
判断 nums 中是否存在三个元素 a,b,c ,使得
 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
 class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
    	vector<vector<int>> result;	//定义一个二维数组
		sort(nums);从小到大进行一个排序
		for(i = 0; i < nums.size(); i++){//i开始从第一个位置遍历数组
			if(nums[i] > 0){
				return false;//如果第一个数就大于0 后面的b加c 就不能为=0了 
			}	
			if(i > 0 && nums[i] ==nums[i - 1]) {
				continue;//这里就是进行对i的去重操作,注意是 nums[i] ==nums[i - 1]才能跳过进入下一次循环
				 
			}
			left = i + 1;
			right = nums.size() - 1;
			while(right > left){//若rig = left 说明指向同一个元素,则没有满足abc三个数,不能行 
				if (nums[i] + nums[left] + nums[right] > 0) right--;//移动指针 
                else if (nums[i] + nums[left] + nums[right] < 0) left++;//移动指针 
                else{//即等于0时的情况 
                	result.push(vector<int>{nums[i], nums[left], nums[right]});//收获三元组结果 
					// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                    while (right > left && nums[right] == nums[right - 1]) right--;//right和前一位相等则 左移 
                    while (right > left && nums[left] == nums[left + 1]) left++; //left和后一位相等 右移
					// 收获结果时,双指针同时收缩
                    right--;
                    left++; 
				}
			}
	}
	return result; 
	}
}

标签:map,四数,15,nums,ran,随想录,right,数组,left
From: https://www.cnblogs.com/lijian-allan/p/17204915.html

相关文章

  • 代码随想录day24|回溯基础、77. 组合
    回溯法,一般可以解决如下几种问题:组合问题:N个数里面按一定规则找出k个数的集合切割问题:一个字符串按一定规则有几种切割方式子集问题:一个N个数的集合里有多少符合条件的......
  • 代码随想录-数组
    二分查找704.二分查找-力扣(LeetCode)intsearch(int*nums,intnumsSize,inttarget){intleft=0;intright=numsSize-1;intmid=0;i......
  • 代码随想录算法Day38 | 动态规划理论基础 ,509. 斐波那契数 ,70. 爬楼梯 ,746. 使用最
    动态规划理论基础动态规划五步曲:确定dp数组(dptable)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组509.斐波那契数题目链接:509.斐......
  • 代码随想录算法训练营Day38 动态规划
    代码随想录算法训练营代码随想录算法训练营Day38动态规划|理论基础509.斐波那契数70.爬楼梯746.使用最小花费爬楼梯理论基础动态规划,英文:DynamicProgramming,简......
  • P1115 最大子段和
    P1115最大子段和最大子段和题目描述给出一个长度为n的序列a,选出其中连续且非空的一段使得这段和最大。输入格式第一行是一个整数,表示序列的长度n。第二行有n......
  • P1540 [NOIP2010 提高组] 机器翻译
    P1540[NOIP2010提高组]机器翻译[NOIP2010提高组]机器翻译题目背景小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。题目描述这个翻译软件的......
  • 代码随想录训练营day8|第202题. 快乐数、两数之和、第454题.四数相加II
    202.快乐数题目链接:202.快乐数题目描述:编写一个算法来判断一个数n是不是快乐数。「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然......
  • 代码随想录算法Day37 | 738.单调递增的数字
    738.单调递增的数字题目链接:738.单调递增的数字-力扣(LeetCode)思路将数字转换成字符数组形式,然后从后向前遍历,当遇到当前这个数大于后一个数的时候,这个数减一,他的后一......
  • HDLBits(15)3.9
    3电路3.2时序逻辑3.2.1锁存器与触发器(LatchesandFlip-Flops)CreatecircuitfromtruthtableJK触发器的真值表如下图所示,仅使用D触发器和门电路来实现该JK触发......
  • 15. 三数之和
    classSolution{//定义三个指针,保证遍历数组中的每一个结果//画图,解答publicList<List<Integer>>threeSum(int[]nums){//定义一个结果集......