这题典型的动规题嘛,选选与不选的问题。
如果全是上升的自然全选咯,难搞的地方主要是,有些能选的点,不知道该不该选,比如题目中的示例:
由图可知…emmm画得不太直接,反正就是在如果选择了某个位置时最长的情况是多少,方便回溯时直接读取。
dp[i]的含义就是上文了。
转移方程就是 dp[j] = 前面所有小于j点值的数字选择一个最大的+1;
初始化:由于每个位置至少有该位置那一个数字,所以dp数组全部置1.
class Solution {
public static int lengthOfLIS(int[] nums) {
if(nums.length==0){
return 0;
}
int dp[] = new int[nums.length];
Arrays.fill(dp,1);
int max =1;
for(int i=1;i<nums.length;i++){
for(int j=i-1;j>=0;j--){
if(nums[j]<nums[i]){
dp[i] = Math.max(dp[j]+1,dp[i]);
}
}
max = Math.max(dp[i],max);
}
return max;
}
}
还有一种思路,就是dp数组存的是,长度为i时,序列末尾最小的数字是多少(由于,末尾数字最小自然可以后面更有可能接上嘛),然后再二分查找这个数组,找出比本次数字小且最靠右的数字。这种方法能使时间复杂度降为O(n^2);
这以这样想,如果需要兑换n块钱,那么可以用n枚1元硬币(假设有1元硬币),那么更少的硬币数肯定是,将x元用一个x元额度的硬币替换。能够替换的额度越大,所用硬币数最少。
dp[i]:最少多少枚硬币能兑换i元。
转移方程:dp[i] = min(dp[i],dp[i-j]+1);
初始化:由于可能没有一元硬币(也就是说不一定能恰好换开),所以dp数组全部初始化为n+1元(反正一个尽可能大的数字嘛)
class Solution {
public static int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp,amount+1);
dp[0] = 0;
for(int i=1;i<=amount;i++){
for(int j=0;j<coins.length;j++){
if(i>=coins[j]) {
dp[i] = Math.min(1 + dp[i - coins[j]], dp[i]);
}
}
}
return dp[amount]>amount?-1:dp[amount];
}
}
本来俺以为这是一道数学题(看了答案还真有数学解)。
想着有俩瓶子,就是不断的倒(三种操作),然后不断变化水量,使它总和为目标值,或者所有状态遍历完了都不行。
那么想一哈一共有几种情况。
- x倒掉
- y倒掉
- x倒入y,x能倒完。
- x倒入y,x不能倒完。
- y倒入x,y能倒完。
- y倒入x,y不能倒完。
- 倒满x
- 倒满y
那么就阔以就按这种思路写就好啦。
所有的情况我没有画完,看这花里胡哨的,总之我们得出,几乎状态之间都能相互转换,所以我们需要用一个啥记录哪些状态有没有走过。
class Solution {
public static boolean canMeasureWater(int x, int y, int z) {
if (z > x + y) {
return false;
}
if (z == 0 || x == 0 || y == 0) {
return z == 0 || (x + y == z);
}
Queue<int[]> bfs = new LinkedList<>();
Set<State> set = new HashSet<>();
bfs.add(new int[]{0, 0});
while (!bfs.isEmpty()) {
int[] in = bfs.poll();
if(in[0]+in[1]==z){
return true;
}
State s = new State(in[0],in[1]);
if(set.contains(s)){
continue;
}
set.add(s);
bfs.add(new int[]{in[0],y});
bfs.add(new int[]{x,in[1]});
int k =in[0]+in[1]-y;
bfs.add(new int[]{k<0?0:k,k<0?(in[0]+in[1]):y});
k = in[1]+in[0]-x;
bfs.add(new int[]{k<0?(in[0]+in[1]):x,k<0?0:k});
bfs.add(new int[]{0,in[1]});
bfs.add(new int[]{in[0],0});
}
return false;
}
}
class State{
int x,y;
State(int xx,int yy){
x=xx;
y=yy;
}
@Override
public boolean equals(Object obj) {
if(obj == this){
return true;
}
if(obj==null||getClass()!=obj.getClass()){
return false;
}
State s = (State) obj;
return s.x==x&&s.y==y;
}
@Override
public int hashCode() {
return Objects.hash(x,y);
}
}
这题贼简单,用dfs遍历所有的情况即可,不过注意不满足条件的不能加入进去,比如互不配对的情况。
配对需要满足的条件是,再加括号时,左括号总比右括号用得多,然后,左括号数只能有n个。
class Solution {
public static List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<>();
dfs(ans,n,n,new StringBuilder());
return ans;
}
private static void dfs(List<String> ans,int right,int left,StringBuilder s){
if(right==0&&left==0){
ans.add(String.valueOf(s));
s.deleteCharAt(s.length()-1);
return;
}
if(right>0) {
dfs(ans, right - 1, left, s.append("("));
}
if(left>right) {
dfs(ans, right, left - 1, s.append(")"));
}
if(s.length()!=0) {
s.deleteCharAt(s.length() - 1);
}
}
}
由于俺,一开始左右写错了,就反着看吧。