leetcode-17-电话号码的字母组合(letter combination of a phone number)-java
在类中建立一个数字对应字母的map,和对应的结果list
方法1:
进入combine("",digits)
第一个字符串为当前字符串,后面的为还能加上的数字字符串
每次从数组字符串中取最前一位,得到对应的char数组,将nowStr+对应的数组(用for循环,分别加几次),然后再次combine
如果remain为“”,说明一小次循环完成,将nowstr加入result
可以将hashmap 改为char[][]数组,每个数字的字母放在对应的地方
方法2:
public void combine(String digits,List
nowIndex为这次进入方法的深度,即在digits的哪个i,根据那个字符得到nowChars数组,进行循环
进入:combine(digits, result, "", 0);
递归方法:每次 combine(digits, result, beforString+nowChars[i], nowIndex+1);
结束条件:nowIndex==digits.length()
leetcode-22-括号生成(generate parentheses)-java
nowstr为当前字符串,left为剩下的左括号,right为剩下的右括号
递归方法:如果right>left说明左边已经有多的( 接下来))或者()都可以,可以加右括号
如果left>0说明left有多的,可以加左括号
结束条件:如果left=right=0 说明此次结束,加入result
leetcode-46-全排列(permutations)-java
解法1(成功,8ms,较慢)
在类中建立一个result的变量,放置结果
建立permutateRemain函数,变量为上一次的全排列几位的list(now)和还能排的数字的list(remain)
在函数中,
如果remain剩余的量为0,将now加入result
对remain进行遍历,在遍历中
遍历的数字为now
先建立一个对now的copy newlist,将newlist加入now
然后将remain除去now,进行新的permutateRemain,然后在remain重新加入now,结束遍历
如何对一个hashset遍历时,还对它进行add,remove操作:
方法1:不用hashset作为剩余集合,用ArrayList,传入下标,将first与first之后的数字一一交换,从而遍历。
方法2:用ArrayList,创建一个visited数组,来得到哪个数字已经被遍历了
leetcode-78-子集(subsets)-java
解法0:
就是从数组,先处理一定有nums[index]的情况,再处理一定没有nums[index]的情况。
但处理没有xxx情况时,调用combine2方法,不把now加入,因为调用combine2方法的方法x,里面的now与combine2的now相同,已经加入过了
解法1(别人的)
不错的方法
https://blog.csdn.net/wodedipang_/article/details/52996928
使用位操作,不使用递归。首先,计算一下该数组nums一共有多少个子集,设数组nums的长度为n,那么它的子集总数为num=2^n。
设置一个变量index,其初始值为1。那么从0到2^n-1中数,对于每一个数i,用index(从1到10,100,100(2进制))与这个i进行与操作,如果得出的结果大于0,则把该数输入到List<>中取,比较n次,因为数组的长度为n。
解法2(别人的)
回溯算法
这道题需要求给定数组的子集,特别要求有:
1、必须是升序
2、不能出现重复的
所以做法其实也就是,首先排序,然后回溯。。和昨天那题一样,可以回去看一下。记得选择下一个的时候,别和当前的值重复就可以了。
解法3(别人的)
回溯算法|递归实现
本解法采用回溯算法实现,回溯算法的基本形式是“递归+循环”,正因为循环中嵌套着递归,递归中包含循环,这才使得回溯比一般的递归和单纯的循环更难理解,其实我们熟悉了它的基本形式,就会觉得这样的算法难度也不是很大。原数组中的每个元素有两种状态:存在和不存在。
① 外层循环逐一往中间集合 temp 中加入元素 nums[i],使这个元素处于存在状态
② 开始递归,递归中携带加入新元素的 temp,并且下一次循环的起始是 i 元素的下一个,因而递归中更新 i 值为 i + 1
③ 将这个从中间集合 temp 中移除,使该元素处于不存在状态
解法4(别人的)
组合|非递归实现
这种方法是一种组合的方式
① 最外层循环逐一从 nums 数组中取出每个元素 num
② 内层循环从原来的结果集中取出每个中间结果集,并向每个中间结果集中添加该 num 元素
③往每个中间结果集中加入 num
④将新的中间结果集加入结果集中
leetcode-79-单词搜索(word search)-java
使用回溯算法,对board中每个与word首字母相同的字符ij,开启begin函数
begin中
如果result已经为true,不再继续
如果char[i][j]与word首字母不同,不再继续
如果相同,
如果word长度为1,说明已经到最后一步,result=true
否则,char[i][j]='*',因为让接下来的操作不到这一位
然后newWord=word截去首位的字符串
然后根据i,j的位置,对上下左右进行begin
最后char[i][j]=now,恢复
也可以char[i][j]='*',换成一个boolean二维数组,记录跑过的地方
leetcode-131-分割回文串-java
1、每一个结点表示剩余没有扫描到的字符串,产生分支是截取了剩余字符串的前缀;
2、产生前缀字符串的时候,判断前缀字符串是否是回文。
如果前缀字符串是回文,则可以产生分支和结点;
如果前缀字符串不是回文,则不产生分支和结点,这一步是剪枝操作。
3、在叶子结点是空字符串的时候结算,此时从根结点到叶子结点的路径,就是结果集里的一个结果,使用深度优先遍历,记录下所有可能的结果。
采用一个路径变量 path 搜索,path 全局使用一个(注意结算的时候,需要生成一个拷贝),因此在递归执行方法结束以后需要回溯,即将递归之前添加进来的元素拿出去;
path 的操作只在列表的末端,因此合适的数据结构是栈。
验证回文串那里,每一次都得使用“两边夹”的方式验证子串是否是回文子串。
于是思考“用空间换时间”,利用动态规划把结果先算出来,这样就可以以 O(1) 的时间复杂度直接得到一个子串是否是回文。
leetcode-212-单词搜索 II-java
先构建一个字典树,内部结构是char[],然后将字典树的root节点进入回溯,不断回溯时,当前i,j改变时,节点也不断进入下一层。
leetcode-301-删除无效的括号-java
主要的思想是使用回溯法,每走到一个括号,要么使用这个括号,要么不使用这个括号,直到遍历完字符串每个字符后,检查最后字符串的有效性。现在主要的问题是如何对回溯过程进行剪枝。
从题意中要求删去最少个数的括号可以想到,需要删除的左右括号数在递归开始前就可以确定下来,首先对字符串进行一次遍历,用deleteLeft记录当前未匹配的左括号数,用deleteRight记录需要删除的右括号数,因为只能删除不能增加,遇到一个右括号时,若deleteLeft为0,就必定要删除一个多余的右括号,deleteRight加一,若deleteLeft大于0,则该右括号可以与前面一个未匹配的左括号匹配,deleteLeft减一。遍历结束后,剩余的deleteLeft就是需要删除的多余的左括数。
进入递归后,同样用一个数leftCount记录当前构建的字符串中未匹配的左括号数,因为事先已经确定了需要删除的左右括号总数,遇见一个左括号,要deleteLeft大于零才能走到删除该左括号的分支,右括号同理。此外,对于左括号,由于不能确定保留它最后能否形成有效的字符串,所以所有左括号都一定可以走到保留它的分支,到最后递归终点处再由deleteLeft == 0判断是否有冗余的左括号。而对于右括号,当发现leftCount == 0时,若保留该右括号则必定不能形成一个有效字符串,所以可以直接在这里进行剪枝。
leetcode-44-通配符匹配-java
解法1
动态规划
(一)状态
f[i][j]表示s1的前i个字符,和s2的前j个字符,能否匹配
(二)转移方程
如果s1的第 i 个字符和s2的第 j 个字符相同,或者s2的第 j 个字符为 “?”
f[i][j] = f[i - 1][j - 1]
如果s2的第 j 个字符为 *
若s2的第 j 个字符匹配空串, f[i][j] = f[i][j - 1]
若s2的第 j 个字符匹配s1的第 i 个字符, f[i][j] = f[i - 1][j]
这里注意不是 f[i - 1][j - 1], 举个例子就明白了 (abc, a*) f[3][2] = f[2][2]
(三)初始化
f[0][i] = f[0][i - 1] && s2[i] == *
即s1的前0个字符和s2的前i个字符能否匹配(是否s2的前i个字符都是*)
(四)结果
f[m][n]
leetcode-10-正则表达式匹配-java
解法1
回溯法
如果模式串中有星号,它会出现在第二个位置,即 pattern[1] 。这种情况下,我们可以直接忽略模式串中这一部分,或者删除匹配串的第一个字符,前提是它能够匹配模式串当前位置字符,即 pattern[0]。如果两种操作中有任何一种使得剩下的字符串能匹配,那么初始时,匹配串和模式串就可以被匹配。
解法2
因为题目拥有 最优子结构 ,一个自然的想法是将中间结果保存起来。我们通过用 dp(i,j)表示 text[i:]和 pattern[j:] 是否能匹配。我们可以用更短的字符串匹配问题来表示原本的问题。
我们用中同样的回溯方法,除此之外,因为函数 match(text[i:], pattern[j:]) 只会被调用一次,我们用 dp(i, j)来应对剩余相同参数的函数调用,这帮助我们节省了字符串建立操作所需要的时间,也让我们可以将中间结果进行保存。