当前位置: 首页 > news >正文

网站的banner做多大郑州网站制作工具

网站的banner做多大,郑州网站制作工具,创新网站建设工作,公司名称怎么取名算法题 Leetcode 39. 组合总和 题目链接:39. 组合总和 大佬视频讲解:组合总和视频讲解 个人思路 这道组合题主要是有总和的限制,当递归和超过了总和就return,递归时加上回溯去遍历数组。 解法 回溯法 把组合问题抽象为如下树形结构 如上…

 算法题

Leetcode 39. 组合总和

题目链接:39. 组合总和

大佬视频讲解:组合总和视频讲解

 个人思路

这道组合题主要是有总和的限制,当递归和超过了总和就return,递归时加上回溯去遍历数组。

解法
回溯法

把组合问题抽象为如下树形结构

如上图,因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制只要选取的元素总和超过target,就返回

回溯法三部曲

1.递归函数参数

定义两个全局变量,二维数组result存放结果集,数组path存放符合条件的结果。

首先是题目中给出的参数,集合candidates, 和目标值target。

此外还需要定义int型的sum变量来统计单一结果path里的总和,startIndex来控制for循环的起始位置.

关于startIndex的使用:如果是一个集合来求组合的话,就需要startIndex,比如组合三。如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例子:Leetcode 77.组合

2.递归终止条件

终止只有两种情况,sum大于target和sum等于target。sum等于target的时候,需要收集结果

3.单层搜索的逻辑

单层for循环依然是从startIndex开始,搜索candidates集合。

本题元素为可重复选取的。所以在递归时,i不需要加1

剪枝

这道题的剪枝就是对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历

class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {List<List<Integer>> res = new ArrayList<>();Arrays.sort(candidates); // 先进行排序backtracking(res, new ArrayList<>(), candidates, target, 0, 0);return res;}public void backtracking(List<List<Integer>> res, List<Integer> path, int[] candidates, int target, int sum, int idx) {// 找到了数字和为 target 的组合if (sum == target) {res.add(new ArrayList<>(path));return;}for (int i = idx; i < candidates.length; i++) {// 如果 sum + candidates[i] > target 就终止遍历if (sum + candidates[i] > target) break;//剪枝path.add(candidates[i]);backtracking(res, path, candidates, target, sum + candidates[i], i);path.remove(path.size() - 1); // 回溯,移除路径 path 最后一个元素}}
}

时间复杂度:O(n * 2^n));(循环n个元素,2^n表示所有可能的子集数量)

空间复杂度:O(n);(递归栈的深度最多为 n)


 Leetcode  40.组合总和II

题目链接:40.组合总和II

大佬视频讲解:组合总和II视频讲解

个人思路

这道题的集合(数组candidates)有重复元素,但还不能有重复的组合,这是这道题难的关键,思路就是 用一个标记数组标记该元素层次上是否使用过,使用过的就跳过,这样不会出现重复的组合。

解法
回溯法

把组合问题抽象为如下树形结构:

“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过

元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同所以要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重。(强调:树层去重的话,需要对数组排序!)

回溯法三部曲

1.递归函数参数

除开存放数组的集合和符合条件的路径, 这道题需要加一个bool型数组used,用来记录同一树枝上的元素是否使用过。这个集合去重的重任就是used来完成的。

2.递归终止条件

终止条件为 sum > target 和 sum == target

其中sum > target 这个条件可以省略,因为在递归单层遍历的时候,会有剪枝的操作.

3.单层搜索的逻辑

如抽线的树形结构,要去重的是“同一树层上的使用过”,判断逻辑如下:

如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。此时for循环里就应该做continue的操作

所以值为 used[i - 1] == true,说明同一树枝candidates[i - 1]使用过

used[i - 1] == false,说明同一树层candidates[i - 1]使用过

因为同一树层,used[i - 1] == false 才能表示,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。而 used[i - 1] == true,说明是进入下一层递归,去下一个数,所以是树枝上

剪枝

当和大于目标值直接返回,即sum + candidates[i] <= target为剪枝操作

class Solution {LinkedList<Integer> path = new LinkedList<>();List<List<Integer>> ans = new ArrayList<>();boolean[] used;int sum = 0;public List<List<Integer>> combinationSum2(int[] candidates, int target) {used = new boolean[candidates.length];// 加标志数组,用来辅助判断同层节点是否已经遍历Arrays.fill(used, false);// 为了将重复的数字都放到一起,所以先进行排序Arrays.sort(candidates);backTracking(candidates, target, 0);return ans;}private void backTracking(int[] candidates, int target, int startIndex) {if (sum == target) {ans.add(new ArrayList(path));}for (int i = startIndex; i < candidates.length; i++) {if (sum + candidates[i] > target) {break;}// 出现重复节点,同层的第一个节点已经被访问过,所以直接跳过if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {continue;}used[i] = true;sum += candidates[i];path.add(candidates[i]);// 每个节点仅能选择一次,所以从下一位开始backTracking(candidates, target, i + 1);used[i] = false;sum -= candidates[i];path.removeLast();}}
}

时间复杂度:O(n * 2^n));(循环n个元素,2^n表示所有可能的子集数量)

空间复杂度:O(n);(递归栈的深度最多为 n)


 Leetcode  131.分割回文串

题目链接:131.分割回文串

大佬视频讲解:分割回文串视频讲解

 个人思路

既要判断是否为回文子串,还要切割,只能用回溯法了,但不知道如何切割,这是个问题...

解法
回溯法

把分割问题抽象为如下树形结构

其实本题的切割问题类似组合问题

例如对于字符串abcdef:

  • 组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....
  • 切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....

回溯法三部曲

1.递归函数参数

全局变量数组path存放切割后回文的子串,二维数组result存放结果集。 

本题递归函数参数还需要startIndex,因为切割过的地方,不能重复切割

2.递归函数终止条件

按照切割的思想去看,切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止条件。

那么在代码里什么是切割线呢?其实在处理组合问题的时候,递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线

3.单层搜索的逻辑

for (int i = startIndex; i < s.size(); i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串

首先判断这个子串是不是回文,如果是回文,就加入path中,path用来记录切割过的回文子串。

注意切割过的位置,不能重复切割,所以,backtracking(s, i + 1); 传入下一层的起始位置为i + 1

判断回文子串

可以使用双指针法,一个指针从前向后,一个指针从后向前,如果前后指针所指向的元素是相等的,就是回文字符串了。

这里需要一个个判断

class Solution {List<List<String>> result= new ArrayList<>();//结果集Deque<String> path = new LinkedList<>();public List<List<String>> partition(String s) {backTracking(s, 0);return result;}private void backTracking(String s, int startIndex) {//如果起始位置大于s的大小,说明找到了一组分割方案if (startIndex >= s.length()) {result.add(new ArrayList(path));return;}for (int i = startIndex; i < s.length(); i++) {//如果是回文子串,则记录if (isPalindrome(s, startIndex, i)) {String str = s.substring(startIndex, i + 1);path.addLast(str);} else {continue;}backTracking(s, i + 1);//起始位置后移,保证不重复path.removeLast();}}//判断是否是回文串private boolean isPalindrome(String s, int startIndex, int end) {for (int i = startIndex, j = end; i < j; i++, j--) {if (s.charAt(i) != s.charAt(j)) {return false;}}return true;}
}

时间复杂度:O(n * 2^n));(循环n个元素,2^n表示所有可能的子集数量)

空间复杂度:O(n);(递归栈的深度最多为 n)


 以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网

http://www.qdjiajiao.com/news/12822.html

相关文章:

  • 商城网站制作方案seo标题优化裤子关键词
  • 那里做直播网站长春百度网站快速排名
  • 从化网站制作广州头条新闻最新
  • 网站建设运营的成本网络推广公司经营范围
  • 商务网站开发优化大师优化项目有
  • 政府网站建设步骤2022年大事热点新闻
  • 做伦理电影网站邯郸网站seo
  • 网站域名申请怎么做广州广告公司
  • 石家庄小学网站建设指数分布
  • 智慧建设网站今日最新新闻重大事件
  • 有了网站源码 怎么建设网站谷歌paypal官网登录入口
  • 买域名做网站推广都是些什么查网站流量查询工具
  • 佛山做网站格网络营销推广方式包括哪几种
  • wordpress 微信咨询代码seo排名优化推荐
  • 如何建立b2b网站淘宝关键词搜索量查询工具
  • 竞拍网站做烂了合肥网站
  • 响应式环保网站上海seo培训
  • 论坛网站建设流程厦门人才网唯一官方网站
  • 深圳大型网站建设公司附近的成人电脑培训班
  • 怎么建设个网站百度下载免费
  • 学做网站哪里学服务器域名怎么注册
  • 百度用户服务中心人工24小时电话做seo排名好的公司
  • 如何在外管局网站上做a合同腾讯企业qq官网
  • 如何创建网站的第一步seo搜索引擎优化主要做什么
  • 关于人大网站建设公司品牌营销策划
  • 做淘宝的网站有哪些内容吗seo优化主要工作内容
  • 做网站报价明细表家庭优化大师
  • 广东网站建设服务供应商百度竞价推广的技巧
  • 互联网公司怎么找网站建设客户江阴企业网站制作
  • 文化传播集团网站建设2345网址导航下载桌面