日常刷题之77-组合

news2024/9/22 1:21:56

题目

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案
提示:假设 n=5,k=3 就是需要组合出来,长度=3且内容数据是在[1,n]这个区间内的所有可能得组合
同时一个组合里面内个数字只能出现一次,[1,2,3]、[3,2,1]、[2,1,3]...等,这种只要里面的内容相同,尽管顺序不否相同都认为是同一个组合


题解

说实话,刚开始看到这个题,不知道怎么下手,看了看官方的题解,大概理解了思路,然后根据刚才理解的思路和自己的感觉慢慢摸索出最终的结果。
如果还有看了还不理解的同学,可以先用官方的代码打印出来一个结果,看是最终是要一个什么结果

比如我刚开始也看不明吧这个题目想干嘛,然后我尝试用官方的代码打印出来 n=5 k=3 的结果
[[1 2 3] [1 2 4] [1 2 5] [1 3 4] [1 3 5] [1 4 5] [2 3 4] [2 3 5] [2 4 5] [3 4 5]]

然后我就明白了,原来如此

开始动手写思路-思路1

虽然我已经看过了,知道要用递归,但是我在自己写的时候还是将复杂的东西拆分出来,拆成自己可以理解的,容易看懂且方便继续往下想的思路

func combine1(n int, k int) [][]int {
	// 根据题目可以确定 k 不可能大于 n
	mResult := make([][]int, 0)
	mSlice := make([]int, k)
	mIdx := 0

	// 判断当前的组合长度是否满足
	// 秉承一个条件,就是确定第一位是那个数字,后面的数字不能比第一个数字小
	// 然后就是枚举出所有可能的下一位数字的排序,一直重复这个想法

	// 当前的第一个数字确定
	mFirstNum := 1

	// 将这个数插入数组中
	mSlice[mIdx] = mFirstNum

	// 判断这个数组插入的数据是否已经满足足够的数量
	if mIdx == k-1 {
		// 满足,则将这个数组插入到结果集中
		mTempSlice := make([]int, k)
		copy(mTempSlice, mSlice)
		mResult = append(mResult, mTempSlice)
	}

	// 满足的后面就不用插入了,考虑不使用插入的最后这个数据,看是否可以继续替换别的数据继续进行

	return mResult
}
写到这里看是否合理-思路2

上面的代码片段写了后想了想,好像是可行的,既然是可行的,继续完善,当然这里我是知道最后是要用递归写的,所以后续写的思路会偏向递归的想法

func combine2(n int, k int) [][]int {
	mResult := make([][]int, 0)
	mSlice := make([]int, k)
	mIdx := 0

	// ==============================================

	// 当前使用到的数据
	mCurNum := 1
	if mCurNum > n {
		// 当前使用的数字已经超了规定,直接退出就行
	}

	if mIdx >= k {
		// 已经超过数组的长度了,后面的都不用算了,直接可以退出了
	}

	// 后续这里还可以提前预判一波,判断后面剩余的长度能否塞满数组,不能的话也没必要继续下去了

	// 这里直接将这个数插入到数组中
	mSlice[mIdx] = mCurNum
	mIdx++
	mCurNum++

	// 判断当前的数组是否刚好塞满,如果刚好塞满就可以将其插入到返回数组中
	if mIdx == k {
		mTempSlice := make([]int, k)
		copy(mTempSlice, mSlice)
		mResult = append(mResult, mTempSlice)
	} else {
		// 是如果没有塞满,继续刚才的步骤,判断数字大小、数组长度、预判后续长度是否满足 ...
	}

	// 到这里就感觉好像中间部分的数据组合还有遗漏的,上面的部分只考虑到了替换 Slice[k] 这个位置数据,
	// 前面部分都是固定的,前面可能还有很多种组合没有实现

	// 这里就要考虑一下前面部分的,比如现在是第一个数,就不要 1 这个数字插入数组
	mIdx--
	// 前面选择的数字已经自增了,这里将数组的下表调回去,然后进行上面同样的判断计算
	// 先 判断数字大小、数组长度、预判后续长度是否满足 ...

	// ==============================================

	return mResult
}
答案的雏形-思路3

到这里代码应该怎么写的雏形已经出来了,然后以及哪些参数是需要进行传递的,心里大致都会有数了,然后进行代码填充

func execFunc(aResult *[][]int, aSlice []int, aIdx, aCurNum, n int) {
	if aCurNum > n {
		return
	}

	if aIdx >= len(aSlice) {
		return
	}

	// n-aCurNum+1 假设最大值n=5 当前插入数字aCurNum=4 此时5-4+1=2 表示还有2个数(4、5)可以使用
	// 然后加上数组已经插入的个数 aIdx 如果还不够填充数组那么后面的都不会满足条件
	if n-aCurNum+1+aIdx < len(aSlice) {
		return
	}

	aSlice[aIdx] = aCurNum

	if aIdx+1 == len(aSlice) {
		mTempSlice := make([]int, len(aSlice))
		copy(mTempSlice, aSlice)
		*aResult = append(*aResult, mTempSlice)
	}

	// 如果数据还没填满,继续进行(数据填满了也会执行到这里,会在里面的判断直接退出了)
	execFunc(aResult, aSlice, aIdx+1, aCurNum+1, n)
	// 这里就考虑前面部分,假设这里没有将这个值插入到数组中,从而进行下个值的插入
	execFunc(aResult, aSlice, aIdx, aCurNum+1, n)
}

func combine3(n int, k int) [][]int {
	mResult := make([][]int, 0)
	mSlice := make([]int, k)

	execFunc(&mResult, mSlice, 0, 1, n)

	return mResult
}

到这里可以说是结束了,但是这递归方法的参数有点多,并且提交的运行结果内存占用并不是很满意,我想着官方的代码中用到了闭包,我感觉那种好像会省点内存,毕竟在go中方法的入参大部分都是值传递(可以理解为把传进来的参数复制了一份使用的)

另一种写法

在思路完全不变的情况下,使用上官方的套路看看,结果就是确实有点用

func combine4(n int, k int) [][]int {
	mResult := make([][]int, 0)
	mSlice := make([]int, k)
	var mFunc func(aIdx, aCurNum int)

	mFunc = func(aIdx, aCurNum int) {
		if aCurNum > n {
			return
		}

		if aIdx >= k {
			return
		}

		if n-aCurNum+1+aIdx < k {
			return
		}

		mSlice[aIdx] = aCurNum

		if aIdx+1 == k {
			mTempSlice := make([]int, k)
			copy(mTempSlice, mSlice)
			mResult = append(mResult, mTempSlice)
		}

		mFunc(aIdx+1, aCurNum+1)
		mFunc(aIdx, aCurNum+1)
	}

	mFunc(0, 1)

	return mResult
}

提交记录

在这里插入图片描述
在这里插入图片描述


题目来源:力扣题库


一点点笔记,以便以后翻阅。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1546075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

买卖股票的最佳时机1,2,3

买卖股票的最佳时机 力扣题目链接 dp[i][0] 表示第i天持有股票所得最多现金 定义二维数组 两列 &#xff1a;0代表持有股票 1代表不持有股票 行代表第几天 dp[i][0] max(dp[i - 1][0], -prices[i]); 第i天持有股票&#xff1a;两种情况 第一种是昨天就已经持有股票了 所…

电脑桌面记事本便签软件,好用的桌面记事本

在快节奏的生活中&#xff0c;我们常常需要记录一些重要事项&#xff0c;以便随时查看和提醒自己。然而&#xff0c;传统的便签容易丢失、难以管理&#xff0c;让我们感到困扰。在这种情况下&#xff0c;一款好用的电脑桌面便签软件就显得尤为重要。今天&#xff0c;小编为大家…

BIOS中英文对照表

Main菜单&#xff1a;这里记录着电脑的主要信息&#xff0c;比如时间和日期&#xff0c;软盘现在已经不再使用&#xff0c;下面的驱动器中会记录电脑连接的硬盘信息&#xff0c;扩展内存就是电脑的物理内存大小&#xff0c;1024KB1MB&#xff0c;1024MB1GB。 Advanced高级设置&…

【PCL】mac下安装PCL的安装与配置

【PCL】mac下安装PCL的安装与配置 PCL PCL官方文档 PCL&#xff08;Point Cloud Library&#xff09;是在吸收了前人点云相关研究基础上建立起来的大型跨平台开源C编程库&#xff0c;它实现了大量点云相关的通用算法和高效数据结构&#xff0c;涉及到点云获取、滤波、分割、配…

git-怎样把连续的多个commit合并成一个?

Git怎样把连续的多个commit合并成一个&#xff1f; Git怎样把连续的多个commit合并成一个&#xff1f; 参考URL: https://www.jianshu.com/p/5b4054b5b29e 查看git日志 git log --graph比如下图的commit 历史&#xff0c;想要把bai “Second change” 和 “Third change” 这…

Android 系统应用 pk8签名文件转jks或keystore教程

一、介绍 签名文件对于我们在做应用开发中&#xff0c;经常遇到&#xff0c;且签名文件不仅仅是保护应用安全&#xff0c;还会涉及到应用与底层之间的数据共享和API文件等问题。 在Android中&#xff0c;签名文件同样也存在这个问题。但是android中又区分系统应用和普通应用。系…

关于hook ntdll 代码详解

UNHOOK ntdll DWORD unhook() {//创建该结构体用于获取该dll的信息 将所有成员变量初始化为零MODULEINFO mi {};//获取当前内存的ntdll的句柄HMODULE ntdllModule GetModuleHandleA("ntdll.dll");//HANDLE(-1)表示获取当前进程的句柄 该函数用于获取该进程的信息G…

大数据开发扩展shell--尚硅谷shell笔记

大数据开发扩展shell 学习目标 1 熟悉shell脚本的原理和使用 2 熟悉shell的编程语法 第一节 Shell概述 1&#xff09;Linux提供的Shell解析器有&#xff1a; 查看系统中可用的 shell [atguiguhadoop101 ~]$ cat /etc/shells /bin/sh/bin/bash/sbin/nologin/bin/dash/bin/t…

约数个数(数论,蓝桥杯)

题目描述&#xff1a; 给定一个数n&#xff0c;再给出n个数&#xff0c;现在要求你求出这些数的乘积的约数个数总和&#xff0c;结果对1e97取模。 取值范围&#xff1a;1<n<100; 1<ni<2e9; 分析步骤&#xff1a; 第一&#xff1a;要求约数的个数&#xff0c;我们有…

Web举例:防火墙二层,上下行连接交换机的主备备份组网

Web举例&#xff1a;防火墙二层&#xff0c;上下行连接交换机的主备备份组网 介绍了业务接口工作在二层&#xff0c;上下行连接交换机的主备备份组网的Web举例。 组网需求 如图1所示&#xff0c;两台FW的业务接口都工作在二层&#xff0c;上下行分别连接交换机。FW的上下行业…

C++运算符重载中的引用返回

文章目录 引言原因1.为了支持链式调用2.避免不必要的对象创建和复制3.保持语义一致性 引言 在C编程语言中&#xff0c;运算符重载是一项强大的特性&#xff0c;它允许程序员为自定义类型重新定义或重载已有的运算符&#xff0c;从而使得这些类型能够像内置类型一样使用运算符。…

面试八股——redis——集群

0. redis集群的方案 1.主从复制&#xff08;高并发读&#xff09; 一个主节点负责写操作&#xff08;增删改&#xff09;&#xff0c;多个从节点负责查操作。 主从复制是让主节点修改数据之后&#xff0c;将对应数据同步到从节点中。 2.哨兵模式&#xff08;实现高可用&#x…

前端发版上线出现白屏问题

目录 路由配置问题资源缓存问题首屏加载过慢 &#xff1a;喂&#xff0c;你的页面白啦&#xff01; 出现上线白屏的问题有很多&#xff0c;如&#xff1a;配置错误、缓存问题、浏览器兼容问题&#xff0c;根据不同情况去解决。 路由配置问题 问题描述&#xff1a; 在vue开发…

[免费]通义灵码做活动,送礼品,快来薅羊毛!!!

你的编辑器装上智能ai编辑了吗&#xff0c;的确挺好用的。 最近阿里云AI编码搞活动&#xff0c;可以免费体验并且还可以抽盲盒。有日历、马克杯、代金券、等等其他数码产品。 大多数都是日历。 点击链接参与「通义灵码 体验 AI 编码&#xff0c;开 AI 盲盒」 https://develope…

Tableau项目案例-网上超市运营分析

一、数据简要介绍 超市运营分析.xlsx 1、客户分析 交易次数统计 购买次数即购买频率,是指消费者在一定时期内购买某种或某类商品的次数。 用tableau打开excel文件 双击城市字段,会显出出一个地图 类别字段也拖到筛选器上,如上操作相同

深入理解TCP/IP协议:网络通信的基石

提示&#xff1a;本系列文章重点学习TCP/IP协议 深入理解TCP/IP协议&#xff1a;网络通信的基石 简介一、TCP/IP协议的基本原理二、TCP/IP协议的工作机制三、TCP面向连接建立连接&#xff1a;断开连接&#xff1a; 四、分层传输五、TCP流量控制滑动窗口机制流量控制的工作流程优…

Pandoc下载和安装笔记

目录 一、下载 二、安装 1、安装软件 2、测试是否安装成功 Pandoc 的作者是 John MacFarlane&#xff0c;John MacFarlane是美国加州大学伯克利分校的哲学系的一位教授。编写Pandoc 用来生成讲义、课件和网站等。程序开源免费&#xff0c;目前以 GPL 协议托管在 Github 网站…

基于SpringBoot+MyBatis+Vue的电商智慧仓储管理系统的设计与实现(源码+LW+部署+讲解)

前言 博主简介&#x1f468;&#x1f3fc;‍⚕️&#xff1a;国内某一线互联网公司全栈工程师&#x1f468;&#x1f3fc;‍&#x1f4bb;&#xff0c;业余自媒体创作者&#x1f4bb;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f4d5;&#x…

AI高效生成图片,借助参考图,激发无限创意!

在数字化艺术的浪潮中&#xff0c;AI图片生成技术以其高效、便捷的特点&#xff0c;正成为创意领域的新宠。而在这其中&#xff0c;参考图的重要性不言而喻。一张精心挑选的参考图&#xff0c;能够激发AI的创造力&#xff0c;为你呈现出令人惊艳的图片作品。 首先&#xff0c;…

三菱FX系列PLC单键启停程序示例(2种方法)

三菱FX系列PLC单键启停程序示例(2种方法) 前面和大家分享了西门子S7-200SMART PLC中实现单按钮启停的具体方法,可以参考以下链接中的内容: S7-200SMART 中如何实现单按钮启停功能(两种方法)? 本次和大家分享在三菱FX3系列PLC中实现单键启停的具体方法: 如下图所示,第…