首页 > 编程语言 >代码随想录算法训练营第二十二天| 77.组合、216.组合总和、17.电话号码的字母组合

代码随想录算法训练营第二十二天| 77.组合、216.组合总和、17.电话号码的字母组合

时间:2025-01-02 18:55:08浏览次数:3  
标签:dep 组合 int res 随想录 back push 字母组合 array

目录

组合的递归思路来源:

77.组合

216.组合总和

17.电话号码的字母组合

组合的递归思路来源(核心是如何用递归实现多重循环):

(1)用三重循环实现:3个数中选3个数(可重复),求所有可能 

/*
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3
2 1 1
2 1 2
2 1 3
2 2 1
2 2 2
2 2 3
2 3 1
2 3 2
2 3 3
3 1 1
3 1 2
3 1 3
3 2 1
3 2 2
3 2 3
3 3 1
3 3 2
3 3 3 
*/ 
for(int i=1;i<=3;i++)    // 遍历1~3 
{
    for(int j=1;j<=3;j++)    // 遍历1~3 
    {
        for(int k=1;k<=3;k++)    // 遍历1~3 
        {
            cout<<i<<' '<<j<<' '<<k<<'\n';     
        }
    } 
}

(2)用五十重循环实现:在3个数中选50个数(可重复),求所有可能,先把3重循环改造成方便复制粘贴的形式。

int a[105];    // 记录答案
 
for(int i=1;i<=3;i++)	// 遍历1~3 
{
    // 记录第一重循环的数 
	a[1] = i;	
	for(int i=1;i<=3;i++)	// 遍历1~3 
	{
        // 记录第二重循环的数 
		a[2] = i;
		for(int i=1;i<=3;i++)	// 遍历1~3 
		{
            // 记录第三重循环的数 
			a[3] = i;	
            // 输出记录的数 
			for(int i=1;i<=3;i++)	
			{
				cout<<a[i]<<' ';	
			} 
			cout<<'\n';
		}
	} 
}

(3)生成五十个数的惯性思维程序: 

int a[105];    // 记录答案
 
for(int i=1;i<=3;i++)	// 遍历1~3 
{
    // 记录第一重循环的数 
	a[1] = i;	
	for(int i=1;i<=3;i++)	// 遍历1~3 
	{
        // 记录第二重循环的数 
		a[2] = i;
		for(int i=1;i<=3;i++)	// 遍历1~3 
		{
            // 记录第三重循环的数 
			a[3] = i;	
            for(int i=1;i<=3;i++)	// 遍历1~3 
			{
	            // 记录第四重循环的数 
				a[4] = i;	
	            for(int i=1;i<=3;i++)	// 遍历1~3 
				{
		            // 记录第五重循环的数 
					a[5] = i;
					
					...
					
					for(int i=1;i<=3;i++)	// 遍历1~3 
					{
			            // 记录第五十重循环的数 
						a[50] = i;	
						
			            // 输出记录的数 
						for(int i=1;i<=50;i++)	
						{
							cout<<a[i]<<' ';	
						} 
						cout<<'\n';
					}	
				}
			}
		}
	} 
}

(4) 50重写起来费人,将其重复逻辑改造成递归写法

int a[105];
void dfs(int dep)
{
	// 50重循环结束
	if(dep > 50)	 
	{
		// 输出记录的数 
		for(int i=1;i<=50;i++)
		{
			cout<<a[i]<<' '; 
		}
		cout<<'\n'; 
	}
	// 1~50重循环 
	else	
	{
		for(int i=1;i<=3;i++)	// 遍历1~3 
		{
			// 记录第dep重的数 
			a[dep] = i;	 
			
			// 来到下一重循环
			dfs(dep+1);	 
		}
	}
} 

 (5)上述问题改成n重循环实现:n个数中选n个,且必须是递增数据,求所有可能(n<=100)

int a[105];
void dfs(int dep, int n, int last)
{
	// n重循环结束
	if(dep > n)	 
	{
		// 输出记录的数 
		for(int i=1;i<=n;i++)
		{
			cout<<a[i]<<' '; 
		}
		cout<<'\n'; 
	}
	// 1~n重循环 
	else	
	{
		for(int i=last+1;i<=n;i++)	// 上一个数+1 到 n 
		{
			// 记录第dep重的数 
			a[dep] = i;	 
			
			// 来到下一重循环
			dfs(dep+1, i);	 
		}
	}
} 


函数调用:dfs(1, n, 0);    // last = 0,目的是令第一重循环的第一个数是1(0+1)

77.组合

题目链接:77. 组合 - 力扣(LeetCode)

递归分析步骤:
    单层逻辑:
        1~n中取一个数,这个数还要比上一个数大
    终止条件:
        k层嵌套
    函数参数:层数dep, 范围n, 最大个数k, 上一个数last,
        一组答案的数组全局

class Solution 
{
public:

    vector<vector<int>> res;    // 将每组结果存储
    vector<int> vc;   // 存储一组结果
    void dfs(int dep, int n, int k, int last)
    {
        if(dep>k)   // k重循环结束
        {
            res.push_back(vc);
        }
        else
        {
            for(int i=last+1; i<=n; i++)    // 上一个数+1到n
            {
                vc.push_back(i);    // 第dep层 存储一个数
                dfs(dep+1, n, k, i);    // 进入第dep+1层
                vc.pop_back();  // 第dep层的i用过,删除,第dep准备用i++这个数
            }
        }
    }
    vector<vector<int>> combine(int n, int k) 
    {
        dfs(1, n, k, 0);
        return res;
    }
};
https://leetcode.cn/problems/combinations/description/

216.组合总和

题目链接:216. 组合总和 III - 力扣(LeetCode)

class Solution 
{
public:
    unordered_map<int, int> mp; // hash计数:用于记录数据是否用过
    vector<vector<int>> res;    // 将每组结果存储
    vector<int> vc;   // 存储一组结果
    void dfs(int dep, int n, int k, int last, int sum)
    {
        if(dep>k)   // k重循环结束
        {
            if(sum == n)    // 判断和 是否 == n
            {
                res.push_back(vc);
            }
        }
        else
        {
            for(int i=last+1; i<=9; i++)    // 可使用数字:1~9
            {
                if(mp[i] == 0)
                {
                    vc.push_back(i);    // 第dep层 存储一个数
                    mp[i] = 1;  // 把i标记为已用状态
                    if(sum+i <= n)  // 剪枝
                    {
                        dfs(dep+1, n, k, i, sum+i);    // 进入第dep+1层,当前层所计算和sum+i告知下一层
                    }
                    vc.pop_back();  // 第dep层的i用过,删除,第dep准备用i++这个数
                    mp[i] = 0;  // 把i标记为未用状态
                } 
            }
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) 
    {
        dfs(1, n, k, 0, 0);
        return res;
    }
};

17.电话号码的字母组合

题目链接:17. 电话号码的字母组合 - 力扣(LeetCode)

难点:“23”,得到一个2,如何遍历abc,得到a,然后要得到3,得到3,如何遍历“def”。

难点解决:拿数组记录所有数字对应的字符组,字符组有了就可以根据得到的数字进行遍历。

class Solution 
{
public:
    vector<string> array;
    // 将数字所对应的字母存储到array数组中
    void alphaToArray()
    {
        array.push_back("");    // 位置0:空
        array.push_back("");    // 位置1:空
        array.push_back("abc");    // 位置2:abc
        array.push_back("def");    // 位置3:def
        array.push_back("ghi");    // 位置4:ghi
        array.push_back("jkl");    // 位置5:jkl
        array.push_back("mno");    // 位置6:mno
        array.push_back("pqrs");    // 位置7:pqrs
        array.push_back("tuv");    // 位置8:tuv
        array.push_back("wxyz");    // 位置9:wxyz
    }
    vector<string> res;
    void dfs(int dep, string digits, string layer)
    {
        if(dep > digits.size())
        {
            if(layer.size()>0) res.push_back(layer);
        }
        else
        {
            int pos = digits[dep-1] - '0';  // 找到按键位置
            string key = array[pos];    // 得到按键字符
            for(int j=0; j<key.size(); j++)    // 对应按键的字符遍历
            {
                dfs(dep+1, digits, layer + key[j]);
            }
        }
    }
    vector<string> letterCombinations(string digits) 
    {
        alphaToArray();  // 将2~9所对应的 字符组 按照2~9的位置 存储到array数组中
        dfs(1, digits, "");
        return res;
    }
};

标签:dep,组合,int,res,随想录,back,push,字母组合,array
From: https://blog.csdn.net/qq_39882553/article/details/144874097

相关文章

  • 组合索引使用注意事项
    如何创建联合索引联合索引的列顺序非常重要,应遵循以下原则:最左前缀原则:查询条件必须从联合索引的最左列开始,索引才能被有效利用。(不能跳过列,不能颠倒列)查询的选择性:把选择性高的列放在前面。例如,user_id 可能是选择性最高的列,因此放在第一个位置。根据常用的查询分......
  • js 两个数组合并后去重
    functionmergeUnique(arr1,arr2){return[...newSet([...arr1,...arr2])];}//示例使用constarray1=[1,2,3];constarray2=[2,3,4];constmergedArray=mergeUnique(array1,array2);console.log(mergedArray);//输出:[1,2,3,4]在这个例子中......
  • 【组合数学】二项式相关与容斥
    二项式定理\[(a+b)^n=\displaystyle\sum^{n}_{i=0}{\binom{n}{i}a^ib^{n-i}}\]证明:数学方法。\[(a+b)^n=a\times(a+b)^{n-1}=a\timesb\times(a+b)^{n-2}=\dots\]假设我们选了\(k\)个\(a\),我们就需要选\(n-k\)个\(b\),根据乘法原理,可......
  • 代码随想录打卡 Day 3
    代码随想录打卡Day31.哈希表的理论基础哈希表的定义哈希表是根据关键码的值直接访问数据的数据结构,一般用来快速判断一个元素出现在集合中。数组就可以看成是一张哈希表,这张哈希表中的关键字就是数组的索引下标,值就是数组中的元素。哈希表的基本概念哈希表的基本概念包......
  • 代码随想录打卡 Day 2
    代码随想录打卡Day21.链表的定义与操作链表作为基本的数据结构类型,其主要形式有三种:单链表双链表循环链表由于刷代码题平时在OJ上默认定义已经给出,可以直接使用。而在面试/机试时,一般需要需要自己手写链表。因此,正确写出链表的定义是非常有必要的。一个单链表的......
  • 百丽宫22年真题题解——最短路径(排列组合法)
    #include<stdio.h>unsignedlonglonghigh;unsignedlonglonglow;unsignedlonglongfac(intn,intm){unsignedlonglongi,f=1;if(m!=1){for(i=n;i>=n-m+1;i--){f=f*i;}returnf;}elseif(m......
  • 使用js写一个方法求出给定100个不重复的数中找出60个的排列、组合各有多少种
    在前端开发中,要计算100个不重复数中找出60个数的排列数和组合数,可以使用JavaScript编写函数来计算。这里我们不需要真正生成所有的排列或组合,而只需计算它们的数量。排列数计算排列数是指从n个元素中取出m个元素,并按照一定的顺序来排列它们的方式总数。数学上,这通常表示为P(n,m......
  • 组合总和(回溯)
    给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一......
  • 排列组合初步
    排列组合初步1.公式部分排列数从\(n\)个不同元素中任取\(m\)(\(m\leqn\),,\(m\)和\(n\)均为自然数)个元素组成一个排列。排列数公式如下:\(A_{n}^{m}=\frac{n!}{(n-m)!}\)理解:第一个位子有\(n\)个选择,第二个位子有\(n-1\)个选择,以此类推,第\(m\)个有\(n-m+1\)个选择,于是得......
  • 电话号码的字母组合(回溯)
    给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意1不对应任何字母。 示例1:输入:digits="23"输出:["ad","ae","af","bd","be","bf","cd","ce","cf&qu......