leetcode 刷题笔记

String

截取字符串

1) subString();

public String substring(int beginIndex)               
//该子字符串从指定索引处的字符开始,直到此字符串末尾。

  public String substring(int beginIndex, int endIndex)  
//从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该子字符串的长度为 endIndex-beginIndex。  
  
  public static void main(String[] args) {
  String Str = new String("hello wrold");  
  System.out.print("返回值,从第4位截取到字符串末尾 :" );
  System.out.println(Str.substring(4) );

  System.out.print("返回值,从第4位截取到第10位 :" );
  System.out.println(Str.substring(4, 10) );
}


返回值,从第4位截取到字符串末尾 :   o wrold
返回值,从第4位截取到第10:   o wrol



3)split()+正则表达式来进行截取

//逗号分割字符串
String str = "hello, name, 12345, 6789";
String[]  strs=str.split(",");
for(int i=0,len=strs.length;i<len;i++){
    System.out.println(strs[i].toString());
}

hello
name
12345
6789


2)通过StringUtils提供的方法

//与第一种方法效果一样
StringUtils.substring("hello world", 4);     // 返回值,从第4位截取到字符串末尾 : o wrold
StringUtils.substring("hello world", 4, 10); // 返回值,从第4位截取到第10位    :   o wrol

//截取某个字符串之前的字符
StringUtils.substringBefore("hello world", "l"); 
//结果是:he          这里是以第一个”l”,为标准。
StringUtils.substringBeforeLast("hello world", "l");
//结果为:hello wor   这里以最后一个“l”为准。

//截取某个字符串之后的字符
StringUtils.substringAfter("hello world", "l");
//结果是:lo world   这里是以第一个”l”,为标准。
StringUtils.substringAfterLast("hello world", "l");
//结果为:d          这里以最后一个“l”为准。

//截取两个字符串之间隔的字符
StringUtils.substringBetween("hello world", "o");    
//结果是: w   两个o之间的字符串。   
StringUtils.substringBetween("hello world", "l", "r"); 
//结果是: lo wo   第一个字符“l”与第一个字符“r”之间的字符串   
StringUtils.substringsBetween("hello world", "l", "r");
//结果是:数组 [lo wo]   第一个字符“l”与第一个字符“r”之间的字符串,以数组形式返回。   

数组

Arrays

​ Arrays.binarySearch() 查找数组元素,返回下标

import java.util.Arrays;
import java.util.Scanner;

public class Demo01 {
 public static void main(String[] args) {
     int []nums = new int[6];
     nums[0]=3;  nums[1]=2;  nums[2]=4;
     // 返回下标
     System.out.println(Arrays.binarySearch(nums,2)); //1
     //如果找不到元素,返回数组长度+1的负数
     // 6==》 -7  3==》-4
     System.out.println(Arrays.binarySearch(nums,89)); //-7




 }
}


排序

选择排序
 int max = b[0] ,index = 0;
        for (int i = 1; i < b.length; i++) {
            for (int j = i; j <b.length ; j++) {
                if(max<b[i]){
                    max=b[i];
                    index=i;
                }
            }
            int tmp =b[index];
            b[index]=b[i-1];
            b[i-1]=tmp;
            max=b[i];
            index=i;
        }
冒泡排序
  for (int i = 1; i < a.length; i++) {
            for (int j = 0; j < a.length-i; j++) {
                if(a[j]<a[j+1]){
                    int tmp =a[j];
                    a[j]=a[j+1];
                    a[j+1]=tmp;
                }
            }

        }

动态规划

解题5步曲

  1. 确定dp数组(dp table)以及下标的含义

  2. 确定递推公式

  3. dp数组如何初始化

  4. 确定遍历顺序

  5. 举例推导dp数组

爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的⽅法可以爬到楼顶呢?

注意:给定 n 是⼀个正整数。

示例 1:

输⼊: 2

输出: 2

解释: 有两种⽅法可以爬到楼顶。

  1. 1 阶 + 1 阶

  2. 2 阶

示例 2:

输⼊: 3

输出: 3

解释: 有三种⽅法可以爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶

  2. 1 阶 + 2 阶

  3. 2 阶 + 1 阶

思路 : 1阶 1种

​ 2阶 2种

​ 3阶 3种(一次只能爬一阶和二阶,所以只能由第一阶楼梯+2 或者

​ 第二阶楼梯+1 得到 ;)

​ 所以我们得出 f(n)=f(n-1)+f(n-2);

if (n <= 1) {
    return n; // 因为下⾯直接对dp[2]操作了,防⽌空指针
}
 	int []dp = new int[n+1]; 
 	dp[1] = 1;
 	dp[2] = 2;
 for (int i = 3; i <= n; i++) { // 注意i是从3开始的
	 dp[i] = dp[i - 1] + dp[i - 2];
 }
 	return dp[n];


//状态压缩
//节省空间

 if (n <= 1) {
     return n;
 }
 	int dp[3];
 	dp[1] = 1;
 	dp[2] = 2;
 for (int i = 3; i <= n; i++) {
 	int sum = dp[1] + dp[2];
 	dp[1] = dp[2];
 	dp[2] = sum;
 }
	 return dp[2];

扩展 这道题⽬还可以继续深化,就是⼀步⼀个台阶,两个台阶,三个台阶,直到 m个台阶,有多少种⽅法爬

到n阶楼顶

这其实是⼀个完全背包问题

int climbStairs(int n) {
    int dp[] = new int[n+1];
 	dp[0] = 1;
 for (int i = 1; i <= n; i++) {
 	for (int j = 1; j <= m; j++) { // 把m换成2,就可以AC爬楼梯这道题
 		if (i - j >= 0) dp[i] += dp[i - j];
 	}
 }
 	return dp[n];
 }
最小花费爬楼梯

数组的每个下标作为⼀个阶梯,第 i 个阶梯对应着⼀个⾮负数的体⼒花费值 cost[i](下标从 0 开始)。

每当你爬上⼀个阶梯你都要花费对应的体⼒值,⼀旦⽀付了相应的体⼒值,你就可以选择向上爬⼀个阶

梯或者爬两个阶梯。

请你找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。

输⼊:cost = [10, 15, 20]
输出:15
解释:最低花费是从 cost[1] 开始,然后⾛两步即可到阶梯顶,⼀共花费 15 。
示例 2:输⼊:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出:6
解释:最低花费⽅式是从 cost[0] 开始,逐个经过那些 1 ,跳过 cost[3] ,⼀共花费 6

  1. 确定dp数组以及下标的含义

dp[i]的定义:到达第i个台阶所花费的最少体⼒为dp[i]

  1. 确定递推公式

dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]; 最小的加上 花费的体力

  1. dp数组如何初始化

    dp[0]=cost[0] do[1]=cost[1];

    初始化跟斐波那契数列初始化差不多啊!

  2. 确定遍历顺序

    从前到后遍历 , 先得算出最优的 dp[i-1] , dp[i-2]

    int minCostClimbingStairs(int[]cost) {
        int []dp = new int[cost.length];
     
     	dp[0] = cost[0];
     	dp[1] = cost[1];
     	for (int i = 2; i < cost.length; i++) {
     		dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
     	}
     // 注意最后⼀步可以理解为不⽤花费,所以取倒数第⼀步,第⼆步的最少值
     return Math.min(dp[cost.size() - 1], dp[cost.size() - 2]);
    
        
        //状态压缩
        
     int minCostClimbingStairs(int[] cost) {
     	int dp0 = cost[0];
     	int dp1 = cost[1];
     	for (int i = 2; i < cost.size(); i++) {
     		int dpi = Math.min(dp0, dp1) + cost[i];
     		dp0 = dp1; // 记录⼀下前两位
     		dp1 = dpi;
     	}
     	return Math.min(dp0, dp1);
    
不同路径

⼀个机器⼈位于⼀个 m x n ⽹格的左上⻆ (起始点在下图中标记为 “Start” )。

机器⼈每次只能向下或者向右移动⼀步。机器⼈试图达到⽹格的右下⻆(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

  1. dp[i,j]表示 (i,j) 位置的路径数

  2. 递推公式 dp[i,j] = dp[i,j-1] + dp[i-1,j] 只能向下,向右移动

  3. 初始化

    for (int i = 0; i < m; i++) dp[i][0] = 1;
    for (int j = 0; j < n; j++) dp[0][j] = 1;
    
  4. 遍历循序

    从前到后 ,dp数组的值是由前面推出来的

int uniquePaths(int m, int n) {
 	int dp [][] = new int[m][n]; 
 	for (int i = 0; i < m; i++) 
        dp[i][0] = 1;
 	for (int j = 0; j < n; j++)
        dp[0][j] = 1;
 	for (int i = 1; i < m; i++) {
 		for (int j = 1; j < n; j++) {
 			dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
 		}
 	}
 		return dp[m - 1][n - 1];
 }
整数拆分

给定⼀个正整数 n,将其拆分为⾄少两个正整数的和,并使这些整数的乘积最⼤化。 返回你可以获得的

最⼤乘积。

示例 1:

输⼊: 2

输出: 1

解释: 2 = 1 + 1, 1 × 1 = 1。

示例 2:

输⼊: 10

输出: 36

解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

说明: 你可以假设 n 不⼩于 2 且不⼤于 58

  1. dp[]数组含义 , 分拆数字i,可以得到的最⼤乘积为dp[i]。
  2. 递推公式 , dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
  3. 初始化 , dp[2]=1; 0 和 1 是无法拆分成两个正整数的,
  4. 遍历顺序,从前到后,拆分一个整数,得先获得子拆分数的最优解

int integerBreak(int n) {
 	int []dp = new int [n+1];
 	dp[2] = 1;
 	for (int i = 3; i <= n ; i++) {
 		for (int j = 1; j < i - 1; j++) {
 			dp[i] = Math.max(dp[i], Math.max((i - j) * j, dp[i - j] * j));
 		}
 	}
 	return dp[n];
 }

附上另一个版本,更容易理解

int integerBreak(int n) {
	if (n <= 3) 
     	return 1 * (n - 1);
	int []dp = new int [n+1];
 	dp[1] = 1;
 	dp[2] = 2;
 	dp[3] = 3;
 	for (int i = 4; i <= n ; i++) {
 		for (int j = 1; j < i - 1; j++) {
 			dp[i] = max(dp[i], dp[i - j] * dp[j]);
 		}
 	}
 	return dp[n];
 }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值