一个IT小菜鸟不断整理遇到的算法之路~~~~~
如果你有什么常见的好的算法,欢迎评论区留言~~~
文章目录
动态规划
原理
基本思想:
问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,在构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
使用条件:
可分为多个相关子问题,子问题的解被重复使用
分析优化解的结构
递归地定义最优解的代价
自底向上地计算优化解的代价保存之,并获取构造最优解的信息
根据构造最优解的信息构造优化解
动态规划特点:
把原始问题划分成一系列子问题;
求解每个子问题仅一次,并将其结果保存在一个表中,以后用到时直接存取,不重复计算,节省计算时间
自底向上地计算。
整体问题最优解取决于子问题的最优解(状态转移方程)(将子问题称为状态,最终状态的求解归结为其他状态的求解)
例题
LeetCode JAVA解题—300. 最长上升子序列详见方法一
LeetCode-322 零钱兑换
面试题 17.16. 按摩师
198. 打家劫舍
213. 打家劫舍 II
337. 打家劫舍 III(树形动态规划)
887. 鸡蛋掉落
强烈推荐经典买股票问题涉及股票价格变化,交易次数等多变量动态规划问题,并且还有相关题型变种,一共6道,干完十分带劲儿!
股票问题系列通解
贪心算法
堆栈,队列
排序
BFS DFS
有关树的递归965. 单值二叉树
面试题13. 机器人的运动范围
将实际问题转化成代码语言
求最大公约数GCD
快慢指针法
思路:一般处理链表中间节点问题,两个指针 slow 与 fast 一起遍历链表。slow 一次走一步,fast 一次走两步。那么当 fast 到达链表的末尾时,slow 必然位于中间。
876. 链表的中间结点
KMP算法
正则表达式
java的泛型应用
java中Arrays.sort()的几种用法
自定义sort函数排序规则:
一般来讲,sort默认是增序排列
如果想要降序排列: words为数组
Arrays.sort(words, (s1, s2) -> s2.length() - s1.length());
937. 重新排列日志文件
字典树
字典树又名前缀树,Trie树,是一种存储大量字符串的树形数据结构,相比于HashMap存储,在存储单词(和语种无关,任意语言都可以)的场景上,节省了大量的内存空间。
典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计
它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
字典树
820. 单词的压缩编码
有效括号
相信大家经常会遇到关于括号的算法题目
这类题目还是有点难度的
一般涉及括号的题目建议想一想用栈来解答
1111. 有效括号的嵌套深度
1021. 删除最外层的括号
32.最长有效括号 这道题目难度是困难,但代码很简单,思路很好,强烈建议
编辑距离算法
编辑距离算法被数据科学家广泛应用,是用作机器翻译和语音识别评价标准的基本算法。
最直观的方法是暴力检查所有可能的编辑方法,取最短的一个。所有可能的编辑方法达到指数级,但我们不需要进行这么多计算,因为我们只需要找到距离最短的序列而不是所有可能的序列。
有关二进制的
计算机原码,反码,补码
1009. 十进制整数的反码
1022. 从根到叶的二进制数之和
二叉树知识点整理
超详细讲解二叉树知识点干货汇总——概念、遍历+代码(递归、非递归)+递归解题
回文串
“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。
最简单的判断回文串:
public static boolean check(String str){
if(null == str || "".equals(str)){
return false
}
int i = 0;
int j = str.length() - 1;
String[] strings = str.split("");
boolean flag = false;
for (; i <= j; i++,j--) {
if(!strings[i].equals(strings[j])){
return false;
}
}
return true;
}
但一般的不会考这么简单,下面整理了一下相关回文串的题
最长回文子串(强烈推荐官方题解视频中的第三种方法动态规划,简单高效,马拉车算法(Manacher)量力而行)
*算了算了,忍耐不住还是想把第三种方法写出来,哈哈哈~~~~*
思路:动态规划
1.先判别子串两边界的字符是否相同
2.若相同则继续判别中间的子串是否相同
3.相同则true,不同为false
状态:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示子串
s
[
i
.
.
j
]
s[i..j]
s[i..j]是否为回文子串
状态转移方程:
d
p
[
i
]
[
j
]
=
(
s
[
i
]
=
=
s
[
j
]
)
a
n
d
d
p
[
i
+
1
]
[
j
−
1
]
dp[i][j]=(s[i] == s[j]) and dp[i+1][j-1]
dp[i][j]=(s[i]==s[j]) and dp[i+1][j−1]
边界条件:解释当
s
[
i
.
.
j
]
s[i..j]
s[i..j]的长度为2或3的时候不必检查子串是否回文
例如: aba 、aa
j
−
1
−
(
i
+
1
)
+
1
<
2
,
整
理
得
j
−
i
<
3
j-1-(i+1)+1<2,整理得j-i<3
j−1−(i+1)+1<2,整理得j−i<3
初始化:
dp[i][i]=true //显然单个字符是回文串
输出:
在得到一个状态的值为true的时候 , 记录起始位置和长度,填表完成以后截取
如果你还是不明白,看到下面例子一定就恍然大悟了:
字符 | b | a | b | a | b |
---|---|---|---|---|---|
下标 | 0 | 1 | 2 | 3 | 4 |
状态转移方程:
d
p
[
i
]
[
j
]
=
(
s
[
i
]
=
=
s
[
j
]
)
dp[i][j]=(s[i] == s[j])
dp[i][j]=(s[i]==s[j]) and
(
(
j
−
1
<
3
)
o
r
d
p
[
i
+
1
]
[
j
−
1
]
)
((j-1<3) or dp[i+1][j-1])
((j−1<3) or dp[i+1][j−1])
由于dp[i][j]参考它左下方的值:
(1)先升序填列
(2)再升序填行
列为子串右边界,行为左边界
可以看到(0,4)的值取决于(1,3)and (s[i] == s[j])
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | T | F | T | F | T |
1 | T | F | T | F | |
2 | T | F | T | ||
3 | T | F | |||
4 | T |
public class Solutions{
public String longestPalindrome(String s){
int len = s.length();
if(len <2){
return s;
}
int maxlen=1;
int begin =0;
// dp[i][j]表示子串s[i..j]是否为回文子串
boolean [][] dp=new boolean[len][len];
for(int i=0;i<len;++i){
dp[i][i]=true;
}
char[] charArray=s.toCharArray();
for(int j=1;j<len;++j){
for(int i=0;i<j;i++){
if (charArray[i] != charArray[j]){
dp[i][j]=false;
}else{
if (j-i<3){
dp[i][j]=ture;
}else{
dp[i][j]==dp[i+1][j-1];
}
}
//只要dp[i][j]==true成立,就表示子串s[i..j]是回文,此时记录回文长度和起始位置
if(dp[i][j] && j-i+1>maxlen){
maxlen=j-i+1;
begin=i;
}
}
}
return s.substring(begin,begin+maxlen);
}
}
图论问题的解法(dfs\bfs\并查集)
图论问题的一般形式为考察对象之间的连通性问题。将问题转化为对象之间的关系连通图,以边的形式表示两个对象存在关联。
显而易见,这种问题很容易想到用深度优先探索或者是广度优先探索,最近刷题学习到一种新的解决方法并查集,我的理解来讲,就是找老大的问题。
哈哈,打个比方:江湖比武,赢了的人当输了的人的老大,老大和小弟划分为一个团伙,问最终由几个团伙?
ex: A打赢了B,那么A是B的老大。C打赢了A,C变成A的老大。D打赢了F,D是F的老大。最终形成俩个团伙分别是团伙A、B、C和团伙D、F。
用一张江湖比武图展示一下:
并查集就是解决连通图一类的问题的;网上找了并查集的算法,觉得这一篇博客写的不错Java实现并查集大家可以参考一下。
光说不练假把式看完了原理算法,刷几道实战
547. 省份数量
399. 除法求值
岛屿数量