动态规划
剑指offer
7. 斐波那契数列
public class Solution {
public int Fibonacci(int n) {
if(n == 0){
return 0;
}
if(n==1){
return 1;
}
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 1;
for (int k=2; k<=n; k++){
dp[k] = dp[k-1]+dp[k-2];
}
return dp[n];
}
}
8. 跳台阶
public class Solution {
public int JumpFloor(int target) {
if(target == 0){
return 0;
}
if(target == 1){
return 1;
}
//定义状态:dp[i] 为跳上第i阶阶梯的调法
int[] dp = new int[target+1];
dp[1] = 1;
dp[2] = 2;
for(int k = 3; k<=target; k++){
dp[k] = dp[k-1] + dp[k-2];
}
return dp[target];
}
}
9.变态跳台阶
public class Solution {
public int JumpFloorII(int target) {
if(target == 0){
return 0;
}
if(target == 1){
return 1;
}
//确定状态,dp[i] 表示跳到第i阶台阶的跳发
int[] dp = new int[target+1];
dp[1] = 1;
dp[2] = 2;
for(int k=3; k<=target; k++){
dp[k] = 1; //直接跳到第k阶台阶,属于一种跳发
for(int n=1; n<k; n++){
dp[k] = dp[k]+dp[n];
}
}
return dp[target];
}
}
10.矩形覆盖
public class Solution {
public int RectCover(int target) {
if(target == 0){
return 0;
}
if(target == 1){
return 1;
}
int[] dp = new int[target+1];
dp[1] = 1;
dp[2] = 2;
for(int k=3; k<=target; k++){
dp[k] = dp[k-1] + dp[k-2];
}
return dp[target];
}
}
30.连续子数组的最大和
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array.length == 0){
return 0;
}
int[] dp = new int[array.length];
dp[0] = array[0];
int max = array[0];
for(int k=1; k<array.length; k++){
dp[k] = Math.max(array[k], dp[k-1]+array[k]);
max = Math.max(max, dp[k]);
}
return max;
}
}
33.丑数
思路:
丑数 N = k2 * 2 + k3 * 3 + k5 * 5 (k2, k3 , k5 个数不定)
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index == 0){
return 0;
}
int[] dp = new int[index+1];
dp[1] = 1; // dp[k]表示从小到大的第k个丑数
int k2 = 1, k3 = 1, k5 = 1; // 丑数 N = k2 *2 + k3 * 3 + k5 *5
for(int k=2; k<=index; k++){
dp[k] = Math.min(dp[k2]*2, Math.min(dp[k3]*3, dp[k5]*5));
if(dp[k] == dp[k2]*2){
k2++;
}
if(dp[k] == dp[k3]*3){
k3++;
}
if(dp[k] == dp[k5]*5){
k5++;
}
}
return dp[index];
}
}
67. 剪绳子
public class Solution {
public int cutRope(int target) {
int[] dp = new int[target+1];
dp[1] = 1;
// i*(k-i) 表示把k分成两个数,
// i*dp[k-i]把k至少分成三个数,因为dp[k-i]的结果是把k-i至少分成了两个数
for(int k=2; k<=target; k++){
for(int i=1; i<k; i++){
dp[k] = Math.max(dp[k], Math.max(i*(k-i), i*dp[k-i]));
}
}
return dp[target];
}
}
leetcode
53.最大子序和
class Solution {
//动态规划
public int maxSubArray(int[] nums) {
int n = nums.length;
if(n==0){
return 0;
}
//定义状态,dp[i]表示以第i个元素为结尾的连续子序列的最大和
int[] dp = new int[n];
//状态初始化
dp[0] = nums[0];
int max = nums[0];
//以第k个元素结尾的连续子序列的最大和要么是第k个元素本身,要么是第k个元素与以第k-1个元素结尾的子序列和的和
//状态转移方程:dp[k] = Math.max(nums[k], nums[k]+dp[k-1]);
for(int k=1; k<n; k++){
dp[k] = Math.max(nums[k], nums[k]+dp[k-1]);
max = Math.max(dp[k], max);
}
return max;
}
}
121.买卖股票的最佳时机
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
if(n == 0){
return 0;
}
//定义状态,dp[k]表示第k天可以获得的最大利润
int[] dp = new int[n];
dp[0] = 0;
int min = prices[0]; //记录前k-1天中,股票的最低价
int max = dp[0]; //记录k天中可获得的最大利润
//状态转移方程:第k天可以获得的最大利润 = max(第k-1天可以获得的最大利润, 第k天价格 -前k-1天中价格最小值)
for(int k=1; k<n; k++){
dp[k] = Math.max(dp[k-1], prices[k]-min);
min = Math.min(min, prices[k]);
max = Math.max(max, dp[k]);
}
return max;
}
}
343.整数拆分
class Solution {
public int integerBreak(int n) {
//确定状态:dp[k] 表示拆分正整数k后可获得的最大积 k>=2
int[] dp = new int[n+1];
dp[1] = 1;
dp[2] = 1; //2=1+1; 1*1=1
//状态转移方程:dp[k] = max( i*(k-i), i*dp[k-i] ) , 其中 1<=i<k
for(int k=3; k<=n; k++){
dp[k] = 0;
for(int i=1; i<k; i++){
int temp = Math.max(i*(k-i), i*dp[k-i]);
dp[k] = Math.max(temp, dp[k]);
}
}
return dp[n];
}
}
198.打家劫舍
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 0){
return 0;
}
//定义状态,dp[k] 为考虑盗取第[0,k]号房子所取得的最大收益
int[] dp = new int[n];
dp[0] = nums[0];
//状态转移方程,求解dp[k], dp[k] = max( nums[k]+dp[k-2], nums[k-1]+dp[k-3]... )
for(int k=1; k<n; k++){
dp[k] = 0;
for(int i = k; i>=0; i--){
dp[k] = Math.max((nums[i]+(i>=2 ? dp[i-2]:0)), dp[k]);
}
}
return dp[n-1];
}
}
链表
剑指offer
3.从尾到头打印链表
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*
*/
import java.util.*;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> res = new ArrayList<>();
if (listNode == null){
return res;
}
Stack<Integer> stack = new Stack<>();
while(listNode != null){
stack.push(listNode.val);
listNode = listNode.next;
}
int n = stack.size(); //需单独保存一下
for(int i = 0; i<n; i++){
res.add(stack.pop());
}
return res;
}
}
14.链表中倒数第k个结点
/*
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){
return null;
}
if(k == 0){
return null;
}
ListNode slow = head;
ListNode fast = head;
// fast 最终要只想链表的最后一个非空节点
for(int i=0; i<k-1; i++){
fast = fast.next;
if(fast == null){
return null;
}
}
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
15.反转链表
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head == null){
return null;
}
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode sub = cur.next;
cur.next = pre;
pre = cur;
cur = sub;
}
return pre;
}
}
16.合并两个排序的链表
非递归(归并法)解法
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null){
return list2;
}
if(list2 == null){
return list1;
}
ListNode dummyHead = new ListNode(-1);
ListNode cur = dummyHead;
while(list1 != null || list2 != null){
if (list1 == null){
cur.next = list2;
cur = cur.next;
list2 = list2.next;
} else if(list2 == null){
cur.next = list1;
cur = cur.next;
list1 = list1.next;
} else {
if(list1.val < list2.val){
cur.next = list1;
cur = cur.next;
list1 = list1.next;
}else {
cur.next = list2;
cur = cur.next;
list2 = list2.next;
}
}
}
return dummyHead.next;
}
}
递归解法
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null){
return list2;
}
if(list2 == null){
return list1;
}
ListNode node = null;
if(list1.val < list2.val){
node = list1;
node.next = Merge(list1.next, list2);
}else {
node = list2;
node.next = Merge(list1, list2.next);
}
return node;
}
}
25.复杂链表的复制
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
if(pHead == null){
return null;
}
// 1.复制 A->B->C => A->A'->B->B'->C->C'
RandomListNode cur = pHead;
while(cur != null){
RandomListNode node = new RandomListNode(cur.label);
node.next = cur.next;
cur.next = node;
cur = cur.next.next;
}
// 2.复制random
cur = pHead;
while(cur != null){
if(cur.random != null){
cur.next.random = cur.random.next;
}
cur = cur.next.next;
}
// 3.拆分,需要不破坏原链表,拆分成两个独立的链表
cur = pHead;
RandomListNode newCur = pHead.next;
RandomListNode newH