动规篇
前言
本次算法入门训练主要训练以下三个内容:
- 以特殊数据结构为载体的算法结构,比如:数组、链表、栈、二叉树等
- 以考察常见算法思想基础的算法题,比如:动态规划、贪心、回溯等
- 基于某种场景包装下的1和2
提示:以下是本篇文章正文内容
内容
第一题:跳台阶
解题思路:简单dp跟昨天的fib数列解题思路差不多,为了入门并熟悉动态规划做准备。
OJ链接:第一题
public class Solution {
public int jumpFloor(int target) {
//dp
//跳到第n阶台阶,只有两种到法,从第n-2阶台阶开始跳or从第n-1阶台阶开始跳
//定义状态:f(n):第n阶台阶的跳法
//状态转移方程: f(n) = f(n-1) + f(n-2)
//设置初始值:f(1) = 1 f(2) = 2 f(0) = 1;
if(target < 2){
return 1;
}
//从0阶 - target阶
int[] dp = new int[target+1];
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for(int i = 3; i <= target; i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[target];
}
}
第二题:矩形覆盖
解题思路:两种放法竖着放和横着放,注意横着放时你下次的放法也就确定了,我们继续使用dp来处理。
OJ链接:第二题
public class Solution {
public int rectCover(int target) {
//简单dp
//定义状态:f(n):n个2*1的小矩形组成2*n的大矩形的方法
//设置状态转移方程: f(n) = f(n-1)[竖着放] + f(n-2)[横着放]
//定义初始值:f(1) = 1 f(2) = 2 f(0) = 0 (不考虑0);
if(target == 0){
return 0;
}
if(target == 1 || target == 2){
return target;
}
int[] dp = new int[target+1];
dp[1] = 1;
dp[2] = 2;
for(int i = 3; i <= target; i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[target];
}
}
第三题:二进制中1的个数
解题思路:了解 x & (x-1) -> 消除x二进制的最低为1的位,这题就会了且是最优解。
OJ链接:第三题
public class Solution {
public int NumberOf1(int n) {
// x & (x-1) -> 消除x二进制的最低为1的位
int count = 0;
while(n != 0){
n &= n-1;
count++;
}
return count;
}
}
第四题:链表中倒数第k个结点
解题思路:非常简单很多经典的链表题,要了解快慢指针和走差值步。
OJ链接:第四题
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head, int k) {
if (head == null || k <= 0) {
return null;
}
//快慢指针
//1.先让快指针走k步
ListNode fast = head;
ListNode slow = head;
while (k > 0) {
if (fast == null) {
//k大于链表的长度
return null;
}
fast = fast.next;
k--;
}
//2.再让两个指针同时走,快指针走完,慢指针就是倒数第k个节点
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
总结
以上就是今天训练的内容,主要是为了入门动态规划,动态规划的本质就是记录了前一次结果,然后由小问题推及大问题,但是什么题什么时候使用动态规划,还需要大量做题来感悟。