前言: \textcolor{Green}{前言:} 前言:
💞本专栏用于本人刷算法的过程。主要包含刷题中的感受以及知识点缺陷。对于学习者来说可以作为参考。
目前更新的算法内容会比较多,很多都是通过刷题来进行知识点的总结,其中部分来源于网络总结,如有侵权请联系。💞
前几天参加了字节的青训营笔试,感受了一下氛围,可以明显的感受到我可以通过前段时间的题目训练让我在笔试中不至于那么尴尬,相信大家也可以通过训练得到很大的提升,加油奥里给
文章存在时候,会随着博主的学习过程进行不间断更新,只增不减,请放心使用
目前作者正在刷题,如果想一起交流的可以添加联系方式互相学习~~欢迎大家
动态规划
思想:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法。按顺序求解子阶段,前面子问题的解为后面子问题的求解提供信息。
如果某一问题有很多重叠子问题,使用动态规划是最有效的。
动态规划中每一个状态一定是由上一个状态推导出来。
动态规划算法的基本思想是:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果。
题目来源:牛客网
等级:中等
\textcolor{OrangeRed}{等级:中等}
等级:中等
涉及方法:动态规划
👉题目描述
有一种将字母编码成数字的方式: ′ a ′ − > 1 , ′ b − > 2 ′ , . . . , ′ z − > 2 6 ′ 'a'->1, 'b->2', ... , 'z->26' ′a′−>1,′b−>2′,...,′z−>26′。
现在给一串数字,返回有多少种可能的译码结果
数据范围:字符串长度满足
0
<
n
≤
90
0 < n \le 90
0<n≤90
进阶:空间复杂度 '
O
(
n
)
′
O(n)'
O(n)′,时间复杂度 '
O
(
n
)
′
O(n)'
O(n)′
示例1
输入:"12"
返回值:2
说明:2种可能的译码结果(”ab” 或”l”)
示例2
输入:"31717126241541717"
返回值:192
说明:192种可能的译码结果
👉代码编写
👉👉方法1
对于普通数组1-9,译码方式只有一种,但是对于11-19,21-26,译码方式有可选择的两种方案,因此我们使用动态规划将两种方案累计。
import java.util.*;
public class Solution {
/**
* 解码
* @param nums string字符串 数字串
* @return int整型
*/
public int solve (String nums) {
// write code here
if (nums.length() == 1 && nums.charAt(nums.length() - 1) == '0'){
return 0;
}
if (nums.length() == 1){
return nums.length();
}
if (nums.charAt(nums.length() - 1) == '0' &&
nums.charAt(nums.length() - 2) != '1' && nums.charAt(nums.length() - 2) != '2') {
return 0;
}
int dp[] = new int[nums.length() + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= nums.length(); ++i) {
if ((nums.charAt(i - 2) == '1' && nums.charAt(i - 1) <= '9' && nums.charAt(i - 1) > '0')
|| (nums.charAt(i - 2) == '2' && nums.charAt(i - 1) <= '6' && nums.charAt(i - 1) > '0')) {
dp[i] = dp[i - 1] + dp[i - 2];
} else {
dp[i] = dp[i - 1];
}
}
return dp[nums.length()];
}
}
👉👉方法2
👉 注意点
👉 可以提炼的知识
题目来源:牛客网
等级:中等
\textcolor{OrangeRed}{等级:中等}
等级:中等
涉及方法:动态规划
👉题目描述
给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个
a
i
m
aim
aim,代表要找的钱数,求组成
a
i
m
aim
aim的最少货币数。
如果无解,请返回-1.
数据范围:数组大小满足 0 ≤ n ≤ 10000 0 \le n \le 10000 0≤n≤10000, 数组中每个数字都满足 0 < v a l ≤ 10000 0 < val \le 10000 0<val≤10000, 0 ≤ a i m ≤ 5000 0 \le aim \le 5000 0≤aim≤5000
要求:时间复杂度 O ( n × a i m ) O(n \times aim) O(n×aim) ,空间复杂度 O ( a i m ) O(aim) O(aim)。
示例1
输入:[5,2,3],20
返回值:4
示例2
输入:[5,2,3],0
返回值:0
示例3
输入:[3,5],2
返回值:-1
备注:
0
≤
n
≤
10
000
0 \leq n \leq 10\,000
0≤n≤10000
0
≤
a
i
m
≤
5
000
0 \leq aim \leq 5\,000
0≤aim≤5000
👉代码编写
👉👉方法1
import java.util.*;
public class Solution {
/**
* 最少货币数
* @param arr int整型一维数组 the array
* @param aim int整型 the target
* @return int整型
*/
public int minMoney (int[] arr, int aim) {
// write code here
if (aim < 1) {
return 0;
}
int[] dp = new int[aim + 1];
Arrays.fill(dp, aim + 1);
dp[0] = 0;
for (int i = 1; i <= aim; ++i) {
for (int j = 0; j < arr.length; ++j) {
if (arr[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1);
}
}
}
return dp[aim] > aim ? -1 : dp[aim];
}
}
👉 注意点
搞清楚这个最小值是为什么就明白这道题了。
首先要遍历
1
−
a
i
m
1-aim
1−aim元,每种面值都要进行枚举,如果面值没有超过要凑的钱数(
a
r
r
[
j
]
<
=
i
arr[j] <= i
arr[j]<=i)才可以对该值进行维护(
d
p
[
i
]
=
M
a
t
h
.
m
i
n
(
d
p
[
i
]
,
d
p
[
i
−
a
r
r
[
j
]
]
+
1
)
dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1)
dp[i]=Math.min(dp[i],dp[i−arr[j]]+1))。
d p [ i − a r r [ j ] ] + 1 ) dp[i - arr[j]] + 1) dp[i−arr[j]]+1) 这个的意思是 获得缺少当前面值的张数,再加上当前面值的张数 1 1 1 最后得出的结果。
👉 可以提炼的知识
题目来源:牛客网
等级:中等
\textcolor{OrangeRed}{等级:中等}
等级:中等
涉及方法:动态规划
👉题目描述
给定一个长度为 n 的数组 arr,求它的最长严格上升子序列的长度。
所谓子序列,指一个数组删掉一些数(也可以不删)之后,形成的新数组。例如 [1,5,3,7,3] 数组,其子序列有:[1,3,3]、[7] 等。但 [1,6]、[1,3,5] 则不是它的子序列。
我们定义一个序列是 严格上升 的,当且仅当该序列不存在两个下标
i
i
i 和
j
j
j 满足
i
<
j
i<j
i<j且
a
r
r
i
≥
a
r
r
j
arr_i \geq arr_j
arri≥arrj 。
数据范围:
0
≤
n
≤
1000
0\leq n \leq 1000
0≤n≤1000
要求:时间复杂度
O
(
n
2
)
O(n^2)
O(n2), 空间复杂度
O
(
n
)
O(n)
O(n)
示例1
输入:[6,3,1,5,2,3,7]
返回值:4
说明:该数组最长上升子序列为 [1,2,3,7] ,长度为4
👉代码编写
👉👉方法1
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 给定数组的最长严格上升子序列的长度。
* @param arr int整型一维数组 给定的数组
* @return int整型
*/
public int LIS (int[] arr) {
// write code here
int len = arr.length;
if (len == 0) {
return 0;
}
int[] dp = new int[len];
Arrays.fill(dp, 1);
int max = 1;
for (int i = 1; i < len; ++i) {
for (int j = i - 1; j >= 0; j--) {
if (arr[i] >= arr[j]) {
dp[i] = Math.max(dp[j] + 1, dp[i]);
}
}
max = Math.max(dp[i], max);
}
return max;
}
}
👉 注意点
这道题就非常的有意思,我刚开始也没有想明白,后来看了下大佬的做法,原谅我第一次。
第一层循环我们遍历数组的时候从第二个数开始遍历。
第二成循环倒序遍历,从
i
−
1
i-1
i−1开始 到
0
0
0结束,每次都将判断序列以
i
i
i结尾的元素,向前查找,比
a
r
r
[
i
]
arr[i]
arr[i]小的元素,得到它们的dp数组记录上升序列的个数
+
1
+ 1
+1,与
d
p
[
i
]
dp[i]
dp[i] 取最大值即为当前i索引位置 最大上升序列
max的值是当前得到的最大上升子序列与原来的值进行比较。得到我们的最后结果。
👉 可以提炼的知识
题目来源:牛客网
等级:简单
\textcolor{OrangeRed}{等级:简单}
等级:简单
涉及方法:动态规划
👉题目描述
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,子数组最小长度为1。求所有子数组的和的最大值。
数据范围:
1
<
=
n
<
=
2
×
1
0
5
1 <= n <= 2\times10^5
1<=n<=2×105
− 100 < = a [ i ] < = 100 -100 <= a[i] <= 100 −100<=a[i]<=100
要求:时间复杂度为
O
(
n
)
O(n)
O(n),空间复杂度为
O
(
n
)
O(n)
O(n)
进阶:时间复杂度为
O
(
n
)
O(n)
O(n),空间复杂度为
O
(
1
)
O(1)
O(1)
示例1
输入:[1,-2,3,10,-4,7,2,-5]
返回值:18
说明:经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18
示例2
输入:[2]
返回值:2
示例3
输入:[-10]
返回值:-10
👉代码编写
👉👉方法1
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int len = array.length;
int[] dp = new int[len];
dp[0] = array[0];
int max = array[0];
for (int i = 1; i < len; ++i) {
dp[i] = Math.max(dp[i - 1] + array[i], array[i]);
max = Math.max(dp[i], max);
}
return max;
}
}
时间复杂度O(n),空间复杂度O(n)
👉👉方法2
优化上一个动态规划
public int FindGreatestSumOfSubArray(int[] array) {
int sum = 0;
int max = array[0];
for(int i = 0; i < array.length; i++){
// 优化动态规划,确定sum的最大值
sum = Math.max(sum + array[i], array[i]);
// 每次比较,保存出现的最大值
max = Math.max(max, sum);
}
return max;
}
最终我们的时间复杂度O(n),空间复杂度O(1)
这里我们也是用了动态规划但是我们的空间复杂度降低了。仅使用一个 s u m sum sum 和 m a x max max 来进行保存值即可。
👉 注意点
转移方程
d
p
[
i
]
=
M
a
t
h
.
m
a
x
(
d
p
[
i
−
1
]
+
a
r
r
a
y
[
i
]
,
a
r
r
a
y
[
i
]
)
;
dp[i] = Math.max(dp[i - 1] + array[i], array[i]);
dp[i]=Math.max(dp[i−1]+array[i],array[i]); 这个是上一个值与当前值相加与当前值进行比较从而得到目前的最大值。
max的值获得是通过我们原来保存的值上面得到的当前值进行比较。最终得到我们需要的值。
👉 可以提炼的知识
题目来源:牛客网
等级:中等
\textcolor{OrangeRed}{等级:中等}
等级:中等
涉及方法:动态规划
👉题目描述
对于长度为n的一个字符串A(仅包含数字,大小写英文字母),请设计一个高效算法,计算其中最长回文子串的长度。
数据范围:
1
≤
n
≤
1000
1 \le n \le 1000
1≤n≤1000
要求:空间复杂度
O
(
1
)
O(1)
O(1),时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
进阶: 空间复杂度
O
(
n
)
O(n)
O(n),时间复杂度
O
(
n
)
O(n)
O(n)
示例1
输入:"ababc"
返回值:3
说明:最长的回文子串为"aba"与"bab",长度都为3
示例2
输入:"abbba"
返回值:5
示例3
输入:"b"
返回值:1
👉代码编写
👉👉方法1
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param A string字符串
* @return int整型
*/
public int getLongestPalindrome (String A) {
// write code here
int len = A.length();
if (len == 1) {
return 1;
}
boolean[][] dp = new boolean[len][len];
for (int i = 0; i < len; ++i) {
dp[i][i] = true;
}
int maxLen = 1;
for (int j = 1; j < len; ++j) {
for (int i = 0; i < j; ++i) {
if (A.charAt(j) == A.charAt(i)) {
if (j - i == 1) {
dp[j][i] = true;
}else {
dp[j][i] = dp[j - 1][i + 1];
}
if (dp[j][i]) {
maxLen = Math.max(j - i + 1, maxLen);
}
}
}
}
return maxLen;
}
}
空间复杂度 O ( n 2 ) O(n^2) O(n2) 时间复杂度 O ( n 2 ) O(n^2) O(n2)
👉 注意点
这道题也非常有趣,我们也会经常见过,后面我会将类似的也会弄上来让大家学习。
d p [ j ] [ i ] dp[j][i] dp[j][i]的含义为: 从 i − j i - j i−j 的子串是否为回文子串.
有没有办法在Ruby中动态创建数组?例如,假设我想遍历用户输入的书籍数组:books=gets.chomp用户输入:"TheGreatGatsby,CrimeandPunishment,Dracula,Fahrenheit451,PrideandPrejudice,SenseandSensibility,Slaughterhouse-Five,TheAdventuresofHuckleberryFinn"我把它变成一个数组:books_array=books.split(",")现在,对于用户输入的每一本书,我想用Ruby创建一个数组。伪代码来做到这一点:x=0books_array.
我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO
首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟
我正在尝试动态构建一个多维数组。我想要的基本上是这样的(为简单起见写出来):b=0test=[[]]test[b]这给了我错误:NoMethodError:undefinedmethod`test=[[],[],[]]而且它工作正常,但在我的实际使用中,我不会事先知道需要多少个数组。有一个更好的方法吗?谢谢 最佳答案 不需要像您正在使用的索引变量。只需将每个数组附加到您的test数组:irb>test=[]=>[]irb>test[["a","b","c"]]irb>test[["a","b","c"],["d","e","f"]]
如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail
如何在对象上调用方法名称的嵌套哈希?例如,给定以下哈希:hash={:a=>{:b=>{:c=>:d}}}我想创建一个方法,给定上面的散列,执行以下操作:object.send(:a).send(:b).send(:c).send(:d)我的想法是我需要从一个未知的关联中获取一个特定的属性(这个方法不知道,但程序员知道)。我希望能够指定一个方法链来以嵌套哈希的形式检索该属性。例如:hash={:manufacturer=>{:addresses=>{:first=>:postal_code}}}car.execute_method_hash(hash)=>90210
我有一个ruby程序,我想接受用户创建的方法,并使用该名称创建一个新方法。我试过这个:defmethod_missing(meth,*args,&block)name=meth.to_sclass我收到以下错误:`define_method':interningemptystring(ArgumentError)in'method_missing'有什么想法吗?谢谢。编辑:我以不同的方式让它工作,但我仍然很好奇如何以这种方式做到这一点。这是我的代码:defmethod_missing(meth,*args,&block)Adder.class_evaldodefine_method
假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入
这里我想输出带有动态组名的json而不是单词组@tickets.eachdo|group,v|json.group{json.array!vdo|ticket|json.partial!'tickets/ticket',ticket:ticketend}end@ticket是这样的散列{a:[....],b:[.....]}我想要这样的输出{a:[.....],b:[....]} 最佳答案 感谢@AntarrByrd,这个问题有类似的答案:JBuilderdynamickeysformodelattributes使用上面的逻辑我已经
我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n