/秋招突击——7/21——复习{堆——数组中的第K大元素}——新作{回溯——全排列、子集、电话号码的字母组合、组合总和、括号生成}

文章目录

    • 引言
    • 复习
      • 数组中的第K大的最大元素
        • 复习实现
        • 参考实现
    • 新作
      • 回溯模板
      • 46 全排列
        • 个人实现
        • 参考实现
      • 子集
        • 个人实现
        • 参考实现
      • 电话号码的字母组合
        • 复习实现
      • 组合总和
        • 个人实现
        • 参考实现
      • 括号生成
        • 复习实现
    • 总结

引言

  • 昨天的科大讯飞笔试做的稀烂,今天回来好好练习一下,主要是针对下述两种题型,分别是对顶堆还有回溯,对顶堆的题目并不多,主要是回溯。下次再遇到这种题目,直接背模板,然后开始做!

复习

数组中的第K大的最大元素

  • 题目链接

  • 第一次做

  • 第二次做

  • 不知不觉已经是第三次做了,感觉还是有点懵,O(N)的时间复杂度,说明可以遍历多次,但是不能嵌套遍历!想想看哈

复习实现
  • 我还是会使用堆实现,并且发现了如果第一次不会做,那么后续会一直不会做,记不住!这里还是要总结.
  • 这里还是使用了堆排序时间,虽然时间复杂度不满足要求,但是单纯为了练习一下!
class Solution {public int findKthLargest(int[] nums, int k) {//define m is lenght ,and pq to sort the numint m = nums.length;Queue<Integer> pq = new PriorityQueue<>();// traverse the numsfor(int i = 0;i < m;i ++){if(pq.size() < k)   pq.add(nums[i]);else{if(nums[i] > pq.peek()){pq.poll();pq.add(nums[i]);}}}return pq.peek();}
}

在这里插入图片描述

参考实现
  • 这里正确的做法是使用快排进行修改,这里先回顾一下快排的模板
void quickSort(nums q,int l ,int r){if(l >= r) return;int i = l - 1,j = r + 1,x = q[(l + r)>>1];while(i< j){do i ++ ;while(q[i] < x);do j ++ ;while(q[j] > x);if(i < j) swap(q[i],q[j]);}quickSort(q,l,j),quickSort(q,j + 1,r);
}
  • 这样背!虽然很蹩脚,但是能记住就行了,记住了就好些了!
    • 左右相交就返回
    • 左左右右是 ij
    • i加小 j减大
    • i小j大做交换
    • j做划分两边排

这里是要求第K大的数字,所以得改变一下i和j交换的方向,最后的序列应该是从大到小,然后再是找第k大的元素,这道题是记住了!修改的话,就从最后的终止条件开始!

具体实现

class Solution {public int quickSort(int[] nums,int l ,int r,int k){if(l == r)  return nums[k];int i = l - 1,j = r + 1,x = nums[(l + r) >> 1];while(i < j){do i ++;while(nums[i] > x);do j --;while(nums[j] < x);if(i < j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}}if(j >= k)   return quickSort(nums,l,j,k);else return quickSort(nums,j + 1,r,k);}public int findKthLargest(int[] nums, int k) {//define m is lenght ,and pq to sort the numint m = nums.length;// traverse the numsint x = quickSort(nums,0,m - 1,k - 1 );return x;}
}

在这里插入图片描述

新作

回溯模板

void dfs(int[] nums,int idx){// 终止条件if(idx == termination){// 目标操作return;}//迭代内容for(){dfs(nums,idx + 1);// 恢复现场}
}
  • 这里要确定两个东西,一个是总的迭代对象,还有一个是单次迭代的修改内容,下面把下面几个题按照这个模板都分析一下!

  • 全排列

    • n个对象排在n个位置,每一个位置都要迭代一次,然后每一次都要从剩下没有排的对象中选出来的,所以
      • 总的迭代次数:n个位置,终止条件就是迭代n次
      • 单次迭代内容:在可选的选项中随机选择一个。
  • 子集

    • n个对象,其中选择任意一个有几种选择方法,遍历每一个元素,然后根据每一个元素决定是否选中,所以
      • 总的迭代次数:n个对象,终止条件所有元素都决策过了。
      • 单次迭代内容:当前元素是否选中两种情况,选中当前元素,不选中当前元素,
  • 组合总和

    • n个对象,选择其中若干个若干次,形成目标值,所以
      • 总的迭代次数:n个元素,每一个元素都要遍历
      • 单次迭代内容:当前元素选择零次,或者若干次

其实如果能够从树的角度分析,效果会更好,树的深度就是总的迭代次数,单个节点的子节点数也就是树的宽度,就是单次迭代需要考虑的内容

46 全排列

  • 题目链接
    在这里插入图片描述
    注意
  • 所有整数互不相同,不用处理特殊情况。
  • 数组的长度会出现的一的情况,边界情况,需要特殊处理!
个人实现
  • 标准回溯,确定一个模板直接开始写。
    • 终止条件:idx = 0,并将结果加入到res中
    • 迭代条件:遍历剩余的元素,随机加入到临时列表中
class Solution {public List<List<Integer>> res = new ArrayList<>();void dfs(int[] nums,int idx,List<Integer> list,Set<Integer> set){if(idx == 0){res.add(new ArrayList(list));return;}// iterator conditionfor(int i = 0;i < nums.length;i ++){int x = nums[i];if(!set.contains(x)){list.add(x);set.add(x);dfs(nums,idx - 1,list,set);list.remove(list.size() - 1);set.remove(x);}}}public List<List<Integer>> permute(int[] nums) {List<Integer> list = new ArrayList<>();Set<Integer> set = new HashSet<>();dfs(nums,nums.length,list,set);return res;}
}

觉得写的有点繁琐,看看参考的教程是怎么写的

  • 注意,在Java中res.add方法是引用传递,需要创建一个同元素变量的副本才行,不然会越界!
参考实现
  • 明确需要记录的状态

    • 每一个位置具体的位置保存的数字,也就是list
    • 每一个数字的使用情况,使用set
    • 递归到了第几步
  • 他是使用全局变量来声明,没有使用形参传递对应

这里就不写了,基本上都是一致的

子集

  • 题目链接
    在这里插入图片描述
    注意
  • 存在数组为1的特殊情况,可能需要特殊处理
  • 各个元素互不相同
  • 元素有负数的情况
个人实现
  • 刚才那道题目是所有的排列情况,这道题目是所有的组合情况,应该也可以使用回溯实现。这个和刚才相同,不过是在每一次的改变环境的时候,就将结果进行保存!
class Solution {List<Integer> list = new ArrayList<>();Set<Integer> set = new HashSet<>();Set<List<Integer>> res = new HashSet<>();void dfs(int[] nums,int idx){if(idx == nums.length){List<Integer> temp = new ArrayList<>(list);Collections.sort(temp);res.add(temp);}for(int i = 0;i < nums.length;i ++){int x = nums[i];if(!set.contains(x)){set.add(x);list.add(x);List<Integer> temp = new ArrayList<>(list);Collections.sort(temp);res.add(temp);dfs(nums,idx + 1);set.remove(x);list.remove(list.size() - 1);}}}public List<List<Integer>> subsets(int[] nums) {res.add(Arrays.asList());dfs(nums,0);List<List<Integer>> resList = new ArrayList<>();for(List<Integer> x:res){resList.add(x);}return resList;}
}

在这里插入图片描述

上面这样做就不对,得再想想,如果是回溯的话,得更新一下状态的改变,不能直愣愣的添加对应的元素!出来结果了,然后再添加!

  • 好蠢呀,没想到,没想到,既然没想到,记下来,下次肯定能够想到!
参考实现

方法一、DFS
递归的条件

  • 每一个元素只有两种情况,放或者不放,所以遍历这两种情况就行了!
class Solution {List<Integer> list = new ArrayList<>();List<List<Integer>> res = new ArrayList<>();void dfs(int[] nums,int idx){// termiante conditionif(idx == nums.length){res.add(new ArrayList(list));return ;}// traverse all the condition// get  the idx numlist.add(nums[idx]);dfs(nums,idx + 1);list.remove(list.size() - 1);// do not get the idx numdfs(nums,idx + 1);}public List<List<Integer>> subsets(int[] nums) {dfs(nums,0);return res;}
}

在这里插入图片描述

方法二、位运算

  • 将这个问题转化为对应的二进制表示,每一个物体只有放或者不放两种情况,对应就是不同的二进制数,而且全排列的最终结果数量就是 2 n 2^n 2n

具体实现如下
这里刚好练习一下Java中的二进制数是怎么操作的!

class Solution {public List<List<Integer>> subsets(int[] nums) {List<List<Integer>> res = new ArrayList<>();int n = nums.length;// traverse all the binary numfor(int i = 0;i < (1 << n);i ++){List<Integer> temp = new ArrayList<>();for(int j = 0;j < n;j ++){// judge the j is 0 or 1if(((i >> j) & 1) == 1){temp.add(nums[j]);}}res.add(temp);}return res;}
}

电话号码的字母组合

  • 题目链接
  • 第一次做
复习实现
class Solution {Map<Character,List<Character>> map = new HashMap<>();StringBuilder str = new StringBuilder();List<String> res = new ArrayList<>();void dfs(String digits,int idx){if(idx == digits.length()){//System.out.println(str.toString());res.add(str.toString());return;}for(char x:map.get(digits.charAt(idx))){str.append(x);dfs(digits,idx + 1);str.deleteCharAt(str.length() - 1);}}public List<String> letterCombinations(String d) {map.put('2',Arrays.asList('a','b','c'));map.put('3',Arrays.asList('d','e','f'));map.put('4',Arrays.asList('g','h','i'));map.put('5',Arrays.asList('j','k','l'));map.put('6',Arrays.asList('m','n','o'));map.put('7',Arrays.asList('p','q','r','s'));map.put('8',Arrays.asList('t','u','v'));map.put('9',Arrays.asList('w','x','y','z'));    if(d.length() == 0) return res;dfs(d,0);return res;}
}

在这里插入图片描述

  • 没以前使用C++实现起来那么快,写起来也没有那么方便!

组合总和

  • 题目链接
    在这里插入图片描述
    注意
  • 所有元素互不相同
  • 每一个元素可以放很多次
个人实现
  • 这题可以使用两种方式实现
    • 完全背包问题,不过需要记录对应的背包状态,时间复杂度比较低,但是不知道怎么记录满足条件的状态
      • 随便选一个,装满为止;F-V,加上价值,这里价值为零
    • 暴力回溯,时间复杂度高

暴力回溯

class Solution {List<Integer> list = new ArrayList<>();List<List<Integer>> resList = new ArrayList<>();Set<List<Integer>> res = new HashSet<>();// brute dfs to solve the problemvoid dfs(int[] candi,int tar,int temp){if(temp == tar){List<Integer> tempList = new ArrayList(list);Collections.sort(tempList);res.add(tempList);return;}for(int i = 0;i < candi.length;i ++){if(temp + candi[i] <= tar){// put//System.out.println(candi[i]);list.add(candi[i]);dfs(candi,tar,temp + candi[i]);list.remove(list.size() - 1);}}}public List<List<Integer>> combinationSum(int[] candidates, int target) {dfs(candidates,target,0);for(List<Integer> x:res){resList.add(x);}return resList;}
}

在这里插入图片描述
我靠,这个居然能过,也是离谱了!

完全背包问题

class Solution {List<Integer> list = new ArrayList<>();List<List<Integer>> resList = new ArrayList<>();public List<List<Integer>> combinationSum(int[] candidates, int target) {int[] f = new int[target + 1];f[0] = 1;for(int i = 0;i < candidates;i ++){for(int j = candidates[i];j < target;j ++){f[j] = f[j] + f[j - candidates[i]];}}return f[target - 1];}
}
  • 这里只能写成这样,因为我并不知道怎么保存中间状态!

不能用完全背包,完全背包并不能获取中间状态!!

参考实现
  • 只能说我对于的回溯的理解还是不够深刻,两种存放方式
    • 是否放当前的数字,要用深度u控制,防止出现死循环
    • 当前物体一定要放,但是顺序不同,需要set控制是否出现
class Solution {List<Integer> list = new ArrayList<>();List<List<Integer>> resList = new ArrayList<>();void dfs(int[] candidates,int dpt,int tar){if(tar == 0){resList.add(new ArrayList(list));return;}if(dpt == candidates.length)    return;for(int i = 0;i * candidates[dpt] <= tar ;i ++){dfs(candidates,dpt + 1,tar - i * candidates[dpt]);list.add(candidates[dpt]);}    for(int i = 0; i * candidates[dpt] <= tar ;i ++)list.remove(list.size() - 1);}public List<List<Integer>> combinationSum(int[] candidates, int target) {dfs(candidates,0,target);return resList;}
}

在这里插入图片描述
实现起来确实更优!如果放或者不放,还是需要使用的深度进行控制!
无论怎么样,都需要加上的对应idx控制

括号生成

  • 题目链接
  • 第一次学习链接
复习实现
class Solution {// define the structure to store the resultList<String> res = new ArrayList<>();StringBuilder str = new StringBuilder();void dfs(int idx,int n,int l,int r){if(idx == 2 * n && l == r){if(l == r)res.add(str.toString());return ;}// remove the special situationif(r > l  || l > n || r > n)  return;str.append('(');dfs(idx + 1,n,l + 1,r);str.deleteCharAt(str.length() - 1);str.append(')');dfs(idx + 1,n,l ,r + 1);str.deleteCharAt(str.length() - 1);}public List<String> generateParenthesis(int n) {dfs(0,n,0,0);return res;}
}

在这里插入图片描述

上一次写的真丝滑!

vector<string> res;
void dfs(int n,int lc,int rc,string s){/** n表示括号数量,lc表示左括号数量,rc表示右括号数量,s表示字符串*/// 判定什么时候加左括号if (lc == n && rc == n) res.push_back(s); else{// 什么时候加右括号if (lc < n) dfs(n,lc + 1,rc,s + "(");if (lc > rc && rc < n) dfs(n,lc,rc + 1,s + ")");}
}vector<string> generateParenthesis(int n){dfs(n,0,0,"");return res;
}

总结

  • 今天这几道题做完了,算是对于深度有了更加深刻的认识!最好能够画出对应的树形结构,树的高度就是总的迭代次数,树的宽度就是单次迭代需要迭代的内容!
  • 写回溯,还是比写其他算法要轻松很多!
  • 写回溯,一定要画图!写算法一定要画图,转成对应的数据结构!回溯就是可以转成对应的树形结构!
  • 一定要要记得恢复现场,每一步都要恢复现场,因为你的编程习惯是共用一个StringBuilder。

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

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

相关文章

JUC并发编程02-常见方法

start方法与run方法 直接调用run方法-》主线程实现&#xff0c;并不会启动一个新线程。多次调用start方法-》会抛出非法线程异常的错&#xff0c;当线程变成了runnable状态就不能用start方法了。 sleep方法与yield方法 调用sleep会让当前线程从running进入 timed waiting状态…

测试——Junit

内容大纲: 常用的五个注解 测试用例顺序指定 参数化 测试套件 断言 1. 常用的五个注解 1.1 Test 通常情况下,我们输入要写在main方法下,此时我想直接输出: Test void Test01(){System.out.println("第一个测试用例"); } 1.2 BeforeAll AfterAll BeforeALL在Tes…

RK3568笔记四十一:DHT11驱动开发测试

若该文为原创文章&#xff0c;转载请注明原文出处。 记录开发单总线&#xff0c;读取DHT11温湿度 一、DHT11介绍 DHT11是串行接口&#xff08;单线双向&#xff09;DATA 用于微处理器与 DHT11之间的通讯和同步&#xff0c;采用单总线数据格式&#xff0c;一次通讯时间4ms左右…

利用一维数组计算今天是今年的第几天

分析&#xff1a; 在一维数组里初始化12个月份&#xff0c;在进行判断是不是闰年&#xff0c;是闰年就把数组的二月的下标改为29&#xff0c;否则不变就按照平年计算&#xff0c;最后把想要计算的月份减1累加到sum里&#xff0c;在进行计算该月份的天也要累加。例如&#xff1a…

神经网络处理器模拟器的一点思考

一 神经网络处理器 通常基于FPGA的神经网络处理器进行部署某种网络&#xff0c;考虑的因素较多&#xff0c;具体包括网络模型的不同&#xff0c;涵盖不同的算子、激活函数、调度策略等等&#xff1b;具体硬件实现&#xff0c;涉及神经网络处理器并行度、硬件资源消耗&#xff0…

java高级——Collection集合之Set探索(底层为HashMap实现)

java高级——Collection集合之Set探索 前情提要文章介绍继承结构底层代码&#xff08;一张图你就悟了&#xff09;下期预告 前情提要 上一篇文章我们探索了HashMap&#xff0c;详细解说了哈希冲突&#xff0c;红黑树以及Map底层到底是怎么实现的&#xff0c;这一篇我们简单说一…

图像生成(Text-to-Image)发展脉络

这篇博客对 图像生成&#xff08;image generation&#xff09; 领域的经典工作发展进行了梳理&#xff0c;包括重要的一些改进&#xff0c;目的是帮助读者对此领域有一个整体的发展方向把握&#xff0c;并非是对每个工作的详细介绍。 脉络发展&#xff08;时间顺序&#xff0…

气膜工业仓储与气膜体育馆的配置区别—轻空间

气膜工业仓储和气膜体育馆在配置上有明显的区别&#xff0c;这主要是由于它们的使用功能和环境不同所导致的。 结构设计 气膜工业仓储&#xff1a; 主要设计为大跨度、大空间&#xff0c;以便容纳大量货物。 气膜体育馆&#xff1a; 设计注重支撑观众席、运动场地和相关设施&…

Golang | Leetcode Golang题解之第274题H指数

题目&#xff1a; 题解&#xff1a; func hIndex(citations []int) int {// 答案最多只能到数组长度left,right:0,len(citations)var mid intfor left<right{// 1 防止死循环mid(leftright1)>>1cnt:0for _,v:range citations{if v>mid{cnt}}if cnt>mid{// 要找…

One-Class SVM

前提知识&#xff1a;支持向量机&#xff08;SVM&#xff09;-CSDN博客 主要思想 找一个超平面将样本中的正例圈出来&#xff0c;预测就是用这个超平面做决策&#xff0c;在圈内的样本就认为是正样本&#xff0c;圈外的是其他样本&#xff0c;如图1所示&#xff1a; 图1 OSVM…

完整创建一个vite前端项目

目录 1.先创建一个vite项目 2.下载第三方依赖 ① 安装路由vue-router ② 安装vuex全局数据管理 ③ 安装element-plus ④ 安装element-plus图标 ⑤ 安装axios发送请求 ⑥ 完整main.js代码模板 3.开发组件 4.登陆页面开发用例 5. 完整项目代码 废话少说&#xff0c;直接…

【C#】| 与 及其相关例子

按位或&#xff08;|&#xff09; 按位或运算符 | 对两个数的每一位进行比较&#xff0c;如果两个数中至少有一个为 1&#xff0c;则结果位为 1&#xff1b;否则&#xff0c;结果位为0。 1010 (10 in decimal) | 1100 (12 in decimal) ------1110 (14 in decimal) 力扣相关…

【MySQL进阶之路 | 高级篇】EXPLAIN的进一步使用

1. EXPLAIN的四种输出格式 EXPLAIN可以输出四种格式&#xff1a;传统格式&#xff0c;JSON格式&#xff0c;TREE格式以及可视化输出。用户可以根据需要选择使用于自己的格式。 1). 传统格式 传统格式简单明了&#xff0c;输出是一个表格形式。 2). JSON格式 第一种格式中介…

面向对象练习题

代码&#xff1a; public class LL {public static void main(String[] args) { Teacher tnew Teacher("Mike",32,"前端页面",20000);Professor P new Professor("Jack",58,"嵌入式开发",20000);pro p new pro("Bob",34,&q…

【规范】小程序发布,『小程序隐私保护指引』填写指南

前言 &#x1f34a;缘由 『小程序隐私保护指引』小程序发布&#xff0c;每次都躲不开&#xff01; &#x1f3c0;事情起因&#xff1a; 最近在帮朋友弄一个小项目&#xff0c;uniappunicloud壁纸小程序。虽然之前做过不少小程序&#xff0c;但是每次发布正式版本时都有一步『…

WSL的安装

&#x1f3bc;个人主页&#xff1a;金灰 &#x1f60e;作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ &#x1f34a;易编橙终身成长社群&#…

网络初识和网络编程(Java版)

前言 网络已经成为我们日常生活中不可分割的一部分&#xff0c;我们每天都会从网络上得到各种各样的信息&#xff0c;我们也会在网络上传播各种各样的信息&#xff0c;可以说我们使用的软件都是依赖于网络的。作为一个程序猿&#xff0c;在我们未来部署的软件中&#xff0c;客…

【存储学习笔记】1:机械硬盘(Hard Drive Disk)结构和寻址方式

目录 HDD的结构HDD的寻址方式CHS寻址&#xff08;不适用于等密度结构磁盘&#xff09;LBA寻址&#xff08;目前普遍使用的线性寻址方式&#xff09; HDD的寻址速度 HDD的结构 盘面&#xff08;Platter&#xff09;&#xff1a;单面或者双面覆盖着用于记录数据的磁性物质&#x…

《昇思25天学习打卡营第25天|第23天》

今天是打卡的第二十三天&#xff0c;今天学习的是应用实践篇中的计算机视觉中FCN图像语义分割。 首先&#xff0c;是对全卷积网络&#xff08;FCN&#xff09;的简介&#xff0c;语义分割的简介&#xff0c;模型简介&#xff08;1、卷积化&#xff0c;2、上采样&#xff0c;3、…

51单片机嵌入式开发:15、STC89C52RC操作蜂鸣器实现一个music音乐播放器的音乐盒

STC89C52RC操作蜂鸣器实现一个music音乐播放器的音乐盒 1 概述2 蜂鸣器操作方法3 蜂鸣器发出音声4 硬件电路5 软件实现6 整体工程&#xff1a;7 总结 1 概述 要实现一个基于STC89C52RC单片机的音乐盒&#xff0c;可以按照以下步骤进行&#xff1a; &#xff08;1&#xff09;硬…