剑指10-1 斐波那契数列
class Solution {
public int fib(int n) {
int a = 0,b=1,sum;
for(int i=0;i<n;i++){
sum = (a+b)%1000000007;
a=b;
b=sum;
}
return a;
}
}
leetcode 42 接雨水
// v1.0 时间复杂度O(N^2)
class Solution {
public int trap(int[] height) {
// 按列求,每列能接的雨水与左右两侧最高的柱子有关
int res = 0;
int len = height.length;
for(int i=1;i<len-1;i++){
int leftMax = 0;
for(int m=0;m<i;m++){
if(height[m]>leftMax){
leftMax = height[m];
}
}
int rightMax = 0;
for(int n=i+1;n<len;n++){
if(height[n]>rightMax){
rightMax = height[n];
}
}
int max = Math.min(leftMax, rightMax);
if(max>height[i]){
res += max-height[i];
}
}
return res;
}
}
// v2.0 动态规划
class Solution {
public int trap(int[] height) {
// 动态规划,将左边最高的和右边最高的先求出来,不放在for循环中
int res = 0;
int len = height.length;
if(len<3){
return 0;
}
int[] left = new int[len];
int[] right = new int[len];
for(int i = 1;i<len-1;i++){
left[i] = Math.max(left[i-1],height[i-1]);
}
for(int i=len-2;i>=1;i--){
right[i] = Math.max(right[i+1],height[i+1]);
}
for(int i=1;i<len-1;i++){
int max = Math.min(left[i],right[i]);
if(max>height[i]){
res+=(max-height[i]);
}
}
return res;
}
}
// v3.0 双指针
class Solution {
public int trap(int[] height) {
// 双指针,用常量存储leftMax和rightMax
// https://leetcode-cn.com/problems/trapping-rain-water/solution/jie-yu-shui-by-leetcode/327718
int res = 0;
int len = height.length;
int left = 0, right = len-1;
int maxLeft = 0, maxRight = 0;
while(left<=right){
if(maxLeft<maxRight){
res += Math.max(0, maxLeft-height[left]);
maxLeft = Math.max(maxLeft, height[left]);
left++;
}else{
res +=Math.max(0, maxRight-height[right]);
maxRight = Math.max(maxRight, height[right]);
right--;
}
}
return res;
}
}
leetcode 53 最大子序和
class Solution {
public int maxSubArray(int[] nums) {
// f(n) = max{f(n-1)+nums[n],nums[n]}
int res = -100000;
int tmp = -100000;
for(int num:nums){
tmp = Math.max(tmp+num,num);
res = Math.max(res, tmp);
}
return res;
}
}
leetcode 62 不同路径
class Solution {
public int uniquePaths(int m, int n) {
int[][] res = new int[m][n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0||j==0){
res[i][j]=1;
}else{
res[i][j] = res[i][j-1]+res[i-1][j];
}
}
}
return res[m-1][n-1];
}
}
leetcode 72 编辑距离
class Solution {
public int minDistance(String word1, String word2) {
int firLen = word1.length();
int secLen = word2.length();
int[][] matrix = new int[firLen+1][secLen+1];
for(int i=0;i<firLen+1;i++){
matrix[i][0] = i;
}
for(int i=0;i<secLen+1;i++){
matrix[0][i] = i;
}
for(int m=1;m<firLen+1;m++){
for(int n=1;n<secLen+1;n++){
if(word1.charAt(m-1)==word2.charAt(n-1)){
matrix[m][n] = matrix[m-1][n-1];
}else{
matrix[m][n] = Math.min(Math.min(matrix[m-1][n],matrix[m-1][n-1]),matrix[m][n-1])+1;
}
}
}
return matrix[firLen][secLen];
}
}
leetcode 55 跳跃游戏
class Solution {
public boolean canJump(int[] nums) {
// 能跳到的最远位置
int jumpMax = 0;
int len = nums.length;
if(len==1){
return true;
}
for(int i=0;i<nums.length;i++){
jumpMax = Math.max(jumpMax, i+nums[i]);
// 能跳到的最远处为当前位置,且当前位置跳跃距离为0时,返回false
if(jumpMax==i&&nums[i]==0){
return false;
}
if(jumpMax>=len-1){
return true;
}
}
return false;
}
}
leetcode 198 打家劫舍
class Solution {
public int rob(int[] nums) {
int len = nums.length;
if(len==1){
return nums[0];
}
// 偷窃到第i个房间时,能偷窃到的最高金额只与其前两个房间的金额有关
int first = nums[0], second = Math.max(nums[0],nums[1]);
for(int i=2;i<len;i++){
int tmp = second;
second = Math.max(second, first+nums[i]);
first = tmp;
}
return second;
}
}
leetcode 224 最大正方形
class Solution {
public int maximalSquare(char[][] matrix) {
int length = matrix[0].length, height = matrix.length;
int[][] dp = new int[height+1][length+1];
int maxLen = 0;
for(int i=0;i<height;i++){
for(int j=0;j<length;j++){
if(matrix[i][j]=='1'){
dp[i+1][j+1] = Math.min(Math.min(dp[i][j],dp[i+1][j]),dp[i][j+1])+1;
maxLen = Math.max(maxLen, dp[i+1][j+1]);
}
}
}
return maxLen*maxLen;
}
}
leetcode 279 完全平方数
class Solution {
public int numSquares(int n) {
int[] dp = new int[n+1];
int tmp = 1;
for(int i=1;i<n+1;i++){
if(i == tmp*tmp){
dp[i] = 1;
tmp++;
continue;
}
dp[i] = 4;
for(int j=tmp-1;j>=1;j--){
dp[i] = Math.min(dp[i],dp[j*j]+dp[i-j*j]);
}
}
return dp[n];
}
}
leetcode 300 最长递增子序列
// v1.0 动态规划 时间复杂度O(N^2)
class Solution {
public int lengthOfLIS(int[] nums) {
int len = nums.length;
if(nums.length<2){
return 1;
}
int res = 1;
int[] dp = new int[len];
Arrays.fill(dp,1);
for(int i=1;i<len;i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
res = Math.max(res, dp[i]);
}
return res;
}
}
// v2.0 二分查找
class Solution {
public int lengthOfLIS(int[] nums) {
int res = 0;
int[] dp = new int[nums.length];
for(int num:nums){
int i = 0, j=res;
while(i<j){
int mid = (i+j)>>1;
if(dp[mid]<num){
i = mid+1;
}else{
j = mid;
}
}
dp[j] = num;
if(j==res) res ++;
}
return res;
}
}
leetcode 309 最佳买卖股票时机含冷冻期
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][] dp = new int[3][len];
// 不手持股票
dp[0][0] = 0;
// 手持股票
dp[1][0] = -prices[0];
// 冷冻期
dp[2][0] = 0;
for(int i=1;i<len;i++){
// 第i天不手持股票利润最大值(第i-1天不手持股票/第i-1天冷冻期)
dp[0][i] = Math.max(dp[0][i-1], dp[2][i-1]);
// 第i天手持股票(第i-1天手持股票/第i-1天不手持股票且为冷冻期)
dp[1][i] = Math.max(dp[1][i-1], dp[0][i-1]-prices[i]);
// 第i天为冷冻期
dp[2][i] = dp[1][i-1]+prices[i];
}
return Math.max(dp[0][len-1],dp[2][len-1]);
}
}
打家劫舍II
class Solution {
public int rob(int[] nums) {
int len = nums.length;
if(len==1) return nums[0];
//分为两段,分别是0-n-1和1-n
int a=0;
int b=nums[0];
int sum=0;
for(int i=1;i<len-1;i++){
sum = Math.max(b,a+nums[i]);
a=b;
b=sum;
}
int resOne = b;
a=0;
b=nums[1];
sum=0;
for(int i=2;i<len;i++){
sum = Math.max(b,a+nums[i]);
a=b;
b=sum;
}
int resTwo = b;
return Math.max(resOne,resTwo);
}
}
leetcode 337 打家劫舍III
class Solution {
public int rob(TreeNode root) {
int[] arr = robInternal(root);
return Math.max(arr[0],arr[1]);
}
public int[] robInternal(TreeNode root){
if(root==null) return new int[2];
int[] res = new int[2];//res[0]表示偷,res[1]表示不偷
int[] left = robInternal(root.left);
int[] right = robInternal(root.right);
res[0] = left[1]+right[1]+root.val;
res[1] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
return res;
}
}
leetcode 121 买卖股票的最佳时机
class Solution {
public int maxProfit(int[] prices) {
// 动态规划 第i天利润最大值等于第i-1天利润和(第i天价格-前i-1天最低价格)中的最大值
int res = 0;
int minPrice = prices[0];
for(int i=1;i<prices.length;i++){
res = Math.max(res, prices[i]-minPrice);
minPrice = Math.min(minPrice,prices[i]);
}
return res;
}
}
leetcode122 买卖股票的最佳时机
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if(len<2){
return 0;
}
int[][] dp = new int[len][2];
//0表示持有现金,1表示持有股票
dp[0][0] = 0;
dp[0][1] = -prices[0];
for(int i=1;i<len;i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);
}
return dp[len-1][0];
}
}
leetcode 416 分割等和子集
//0-1背包问题
class Solution {
public boolean canPartition(int[] nums) {
int len = nums.length;
int sum = 0;
for(int num:nums){
sum+=num;
}
if((sum&1)==1){
return false;
}
int target = sum>>1;
boolean[] dp = new boolean[target+1]; //状态压缩为一维数组
dp[0] = true;
for(int i=1;i<len;i++){
//倒序更新
for(int j=target;j>=nums[i];j--){
if(dp[target]==true){
return true;
}
dp[j] = dp[j]||dp[j-nums[i]];
}
}
return dp[target];
}
}
leetcode 474
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int len = strs.length;
int[][] dp = new int[m+1][n+1];
for(int i=1;i<=len;i++){
int[] countZeroandOne = count(strs[i-1]);
for(int p=m;p>=countZeroandOne[0];p--){
for(int q=n;q>=countZeroandOne[1];q--){
dp[p][q] = Math.max(dp[p][q],dp[p-countZeroandOne[0]][q-countZeroandOne[1]]+1);
}
}
}
return dp[m][n];
}
public int[] count(String str){
int[] countZeroandOne = new int[2];
for(int i=0;i<str.length();i++){
countZeroandOne[str.charAt(i)-'0']++;
}
return countZeroandOne;
}
}
leetcode 152 乘积最大子数组
//imax维护当前子数组最大值,imin维护当前子数组最小值
//遇到负数时,imax和imin互换
class Solution {
public int maxProduct(int[] nums) {
int res = Integer.MIN_VALUE;
int imax=1;
int imin=1;
for(int num:nums){
if(num<0){
int temp= imax;
imax = imin;
imin = temp;
}
imax = Math.max(imax*num,num);
imin = Math.min(imin*num,num);
res = Math.max(imax,res);
}
return res;
}
}
leetcode 96 不同的二叉搜索树
class Solution {
public int numTrees(int n) {
//设值为n时拥有的种数为G(n),当根节点为1时,左节点为null,右节点有n-1种可能性,
//当根节点为2时,左节点有n-2种可能性...
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for(int i=2;i<n+1;i++){
for(int j=0;j<i;j++){
dp[i] += dp[j] * dp[i-1-j];
}
}
return dp[n];
}
}
以下为背包问题类型:
leetcode 518 零钱兑换II
class Solution {
public int change(int amount, int[] coins) {
//完全背包问题
if(amount==0){
return 1;
}
int[] count = new int[amount+1];
int len = coins.length;
for(int i=0;i<len;i++){
for(int j=coins[i];j<=amount;j++){
if(j==coins[i]){
count[j]=count[j]+1;
continue;
}
count[j] = count[j]+count[j-coins[i]];
}
}
return count[amount];
}
}
leetcode 377 组合总数IV
class Solution {
public int combinationSum4(int[] nums, int target) {
//完全背包问题
//dp[m] = dp[m-nums[0]]+dp[m-nums[1]]+...
int[] dp = new int[target+1];
dp[0] = 1;//m=nums[i]
for(int i=1;i<=target;i++){
for(int num:nums){
if(i>=num){
dp[i] += dp[i-num];
}
}
}
return dp[target];
}
}
leetcode 494 目标和
class Solution {
public int findTargetSumWays(int[] nums, int target) {
// sum(M)-sum(N) = target
// sum(M)-sum(N)+sum(M)+sum(N) = target+sum
// ==> sum(M) = (target+sum)/2
int sum = 0;
for(int num:nums){
sum+=num;
}
if(((target+sum)&1)==1) return 0;
int newTarget = (target+sum)>>1;
if(newTarget<0) return 0;
int[] dp = new int[newTarget+1];
dp[0] = 1;
for(int i=0;i<nums.length;i++){
for(int j=newTarget;j>=nums[i];j--){
dp[j] = dp[j]+dp[j-nums[i]];
}
}
return dp[newTarget];
}
}