1.简单-最大子数组和
1.动态规划
class Solution {
public int maxSubArray(int[] nums) {
int max = nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
for(int i=1;i<nums.length;i++){
if(dp[i-1]>0){
dp[i]= dp[i-1] + nums[i];
}else{
dp[i]= nums[i];
}
if(dp[i]>max){
max = dp[i];
}
}
return max;
}
}
// 首先是动态规划方程
//dp[i]
// 前i-1位的最大值
//dp[i]>0
//dp[i-1]>0
// f(n-1)+nums[i] f(n-1)>0
//f(n)
// nums[i] f(n-1)<0
2.简单-爬楼梯
1.动态规划
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n+1];
if(n==1){
return 1;
}
dp[1]=1;
if(n==2){
return 2;
}
dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
}
// 第一步:首先动态规划方程
//
// f(1)=1;
// f(2)=2;
// f(n) = f(n-1) + f(n-2)
3.简单-比特位计数
1.常规方法
class Solution {
public int[] countBits(int n) {
int[] totalNumber = new int[n+1];
for(int i=1;i<=n;i++){
totalNumber[i] = countNumber(i);
}
return totalNumber;
}
public int countNumber(int n){
int one = 0;
// 对每个数字判断位数
while(n>0){
// 数组换位
n= n&(n-1);
one++;
}
return one;
}
}
2.动态规划
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n+1];
int highBit = 0;
for(int i=1;i<dp.length;i++){
if((i&(i-1))==0){
highBit = i;
}
dp[i] = dp[i-highBit]+1;
}
return dp;
}
}
4.简单-买卖股票的最佳时机
1.暴力破解的方式
public class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0;
for (int i = 0; i < prices.length - 1; i++) {
for (int j = i + 1; j < prices.length; j++) {
int profit = prices[j] - prices[i];
if (profit > maxprofit) {
maxprofit = profit;
}
}
}
return maxprofit;
}
}
2.动态规划方式
class Solution {
public int maxProfit(int[] prices) {
// 买卖股票的最佳时机
int[] dp = new int[prices.length];
dp[0] = prices[0];
int maxProfit = 0;
//dp[i]表示截止到i,价格的最低点是多少 dp[i]=min(dp[i-1],nums[i])
for(int i=1;i<prices.length;i++){
dp[i] = dp[i-1]>prices[i] ?prices[i]:dp[i-1];
maxProfit = prices[i]-dp[i-1]>maxProfit?prices[i]-dp[i-1]:maxProfit;
}
return maxProfit;
}
}
5.中等-括号生成
1.动态规划
简单来说,在求N个括号的排列组合时,把第N种情况(也就是N个括号排列组合)视为单独拿一个括号E出来,剩下的N-1个括号分为两部分,P个括号和Q个括号,P+Q=N-1,然后这两部分分别处于括号E内和括号E的右边,各自进行括号的排列组合。由于我们是一步步计算得到N个括号的情况的,所以小于等于N-1个括号的排列组合方式我们是已知的(用合适的数据结构存储,方便后续调用,且在存储时可利用特定数据结构实现题目某些要求,如排序,去重等),且P+Q=N-1,P和Q是小于等于N-1的,所以我们能直接得到P个和Q个括号的情况,进而得到N个括号的结果!
楼主的算法思想很巧妙,赞一个~这个算法主要的基点就是将排列组合的情况分为了括号内和括号外这两种情况,且仅存在两种情况!至于为什么,原因在于楼主的算法的前提是单独拿出来的括号E的左边在N个括号所有排列组合情况中都是处于最左边,所以不存在括号位于括号E的左边的情况。因此,N-1个括号(拿出了括号E)仅可能分布于括号E内和括号E外,分为两种子情况讨论! 这种思想还可以应用于其他类似的题的求解中,即怎样合理高效的利用前面步骤的计算结果得出当前步骤结果,从而得出最终结果。
class Solution {
public List<String> generateParenthesis(int n) {
ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
if(n == 0){
return result.get(0);
}
ArrayList<String> List0 = new ArrayList<String>();
List0.add("");
result.add(List0);
ArrayList<String> list1 = new ArrayList<String>();
list1.add("()");
result.add(list1);
for(int i = 2;i<=n;i++){
ArrayList<String> temp = new ArrayList<String>();
for(int j =0;j<i;j++){
List<String> str1 = result.get(j);
List<String> str2 = result.get(i-1-j);
for(String s1:str1){
for(String s2:str2){
String e1 = "(" + s1 + ")" +s2;
temp.add(e1);
}
}
}
result.add(temp);
}
return result.get(n);
}
}
// i+j = i-1
2.DFS
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
dfs(n, n, "");
return res;
}
private void dfs(int left, int right, String curStr) {
if (left == 0 && right == 0) { // 左右括号都不剩余了,递归终止
res.add(curStr);
return;
}
if (left > 0) { // 如果左括号还剩余的话,可以拼接左括号
dfs(left - 1, right, curStr + "(");
}
if (right > left) { // 如果右括号剩余多于左括号剩余的话,可以拼接右括号
dfs(left, right - 1, curStr + ")");
}
}
}
6.中等-跳跃游戏
1.思路一:用一个动态规划数组,存储所有可能到达的路径,然后遍历
class Solution {
public static boolean canJump(int[] nums) {
int length = nums.length;
if(length==1){
return true;
}
boolean[] flag = new boolean[nums.length];
flag[0] = true;
//
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<=i+nums[i]&&j<nums.length;j++){
flag[j]=true;
}
}
for(int i=0;i<nums.length;i++){
if(!flag[i]){
return false;
}
}
return true;
}
}
2.思路二:贪心算法
class Solution {
public boolean canJump(int[] nums) {
int rightMax = 0;
for(int i=0;i<nums.length;i++){
// 边界终止条件
if(i<=rightMax){
// 不断更新最大的右边界
rightMax = Math.max(rightMax,nums[i]+i);
if(rightMax>=nums.length-1){
return true;
}
}
}
return false;
}
}
7.中等-零钱兑换
1.动态规划
class Solution {
public 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(coins[j]<=i){
dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
}
}
}
return dp[amount]==amount+1?-1:dp[amount];
}
}
8.最长有效括号
1.动态规划
class Solution {
public int longestValidParentheses(String s) {
int maxans = 0;
int[] dp = new int[s.length()];
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == ')') {
if (s.charAt(i - 1) == '(') {
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
} else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
maxans = Math.max(maxans, dp[i]);
}
}
return maxans;
}
}
2.栈
import java.util.Stack;
class Solution {
public int longestValidParentheses(String s) {
int maxans = 0;
Stack<Integer> stack = new Stack<Integer>();
stack.push(-1);
for(int i =0;i<s.length();i++){
if(s.charAt(i)=='('){
stack.push(i);
} else{
stack.pop();
if(stack.isEmpty()){
stack.push(i);
}else{
maxans = Math.max(maxans,i-stack.peek());
}
}
}
return maxans;
}
}```