柠檬水找零

在找20元的时候使用了贪心算法," 尽可能的找10+5,而不是5+5+5".
java
class Solution {
public boolean lemonadeChange(int[] bills) {
int ten=0;
int five=0;
for(int x:bills){
if(x==5){
five++;
}else if(x==10){
if(five!=0){
five--;
ten++;
}else{
return false;
}
}else{
if(five !=0 && ten!=0){
ten--;
five--;
}else if(five>=3){
five-=3;
}else{
return false;
}
}
}
return true;
}
}
将数组和减半的最小操作次数

2208. 将数组和减半的最少操作次数 - 力扣(LeetCode)
java
class Solution {
public int halveArray(int[] nums) {
PriorityQueue<Double> heap=new PriorityQueue<>((a,b)->b.compareTo(a));
int count=0;
double sum=0.0;
for(int x:nums){
heap.offer((double)x);
sum+=x;
}
sum/=2.0;
while(sum>0){
double t=heap.poll()/2.0;
sum-=t;
count++;
heap.offer(t);
}
return count;
}
}
最大数

java
class Solution {
public String largestNumber(int[] nums) {
int n=nums.length;
String[] str=new String[n];
for(int i=0;i<n;i++){
str[i]=""+nums[i];
}
Arrays.sort(str,(a,b)->{
return (b+a).compareTo(a+b);
});
StringBuffer s=new StringBuffer();
for(String m:str){
s.append(m);
}
if(s.charAt(0)=='0'){
return "0";
}
return s.toString();
}
}
摆动序列

left中存的值是当前节点的与前一个数的差值,right中存的是当前节点和后一个点的差值
java
class Solution {
public int lengthOfLIS(int[] nums) {
int n=nums.length;
int[] dp=new int[n];
int ret=0;
Arrays.fill(dp,1);
for(int i=n-1;i>=0;i--){
for(int j=i+1;j<n;j++){
if(nums[i]<nums[j]){
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
ret=Math.max(ret,dp[i]);
}
return ret;
}
}
最长的递增子序列
可以使用深搜(dfs),也可以使用动态规划,也可以用贪心算法

java
class Solution {
public int lengthOfLIS(int[] nums) {
ArrayList<Integer> ret=new ArrayList();
int n=nums.length;
ret.add(nums[0]);
for(int i=1;i<n;i++){
if(ret.get(ret.size()-1)<nums[i]){
ret.add(nums[i]);
}else{
int left=0;
int right=ret.size()-1;
while(left<right){
int mid=(right+left)/2;
if(ret.get(mid)>=nums[i]){
right=mid;
}else{
left=mid+1;
}
}
ret.set(left,nums[i]);
}
}
return ret.size();
}
}
递增的三元子序列

java
class Solution {
public boolean increasingTriplet(int[] nums) {
int a=nums[0];
int b=Integer.MAX_VALUE;
int n=nums.length;
for(int i=1;i<n;i++){
if(nums[i]>b){
return true;
}else if(nums[i]>a){
b=nums[i];
}else{
a=nums[i];
}
}
return false;
}
}
使用ArrayList+二分查找
java
class Solution {
public boolean increasingTriplet(int[] nums) {
ArrayList<Integer> ret=new ArrayList<>();
ret.add(nums[0]);
int n=nums.length;
for(int i=1;i<n;i++){
if(ret.get(ret.size()-1)<nums[i]){
ret.add(nums[i]);
}else{
int left=0;
int right=ret.size()-1;
while(left<right){
int mid=(left+right)/2;
if(ret.get(mid)>=nums[i]){
right=mid;
}else{
left=mid+1;
}
}
ret.set(left,nums[i]);
}
if(ret.size()>=3){
return true;
}
}
return false;
}
}
最长的连续递增数列

java
class Solution {
public int findLengthOfLCIS(int[] nums) {
int n=nums.length;
int ret=0;
for(int i=0;i<n;){
int j=i+1;
while(j<n && nums[j]>nums[j-1] ){
j++;
}
ret=Math.max(ret,j-i);
i=j;
}
return ret;
}
}
买卖股票的最佳时期

暴力解法->两层for直接暴力枚举
java
class Solution {
public int maxProfit(int[] prices) {
int n=prices.length;
int result=0;
for(int i=0;i<n;i++){
int j=i+1;
int ret=0;
while(j<n && prices[j]>prices[i]){
ret=Math.max(ret,prices[j]);
j++;
}
result=Math.max(result,ret-prices[i]);
}
return result;
}
}
贪心->优化暴力解法
java
class Solution {
public int maxProfit(int[] prices) {
int n=prices.length;
int prevMin=Integer.MAX_VALUE;
int ret=0;
for(int i=0;i<n;i++){
ret=Math.max(ret,prices[i]-prevMin);
prevMin=Math.min(prevMin,prices[i]);
}
return ret;
}
}
买卖股票的最佳时期Ⅱ
122. 买卖股票的最佳时机 II - 力扣(LeetCode)

使用双指针的方法
java
class Solution {
// 双指针的方法
public int maxProfit(int[] prices) {
int n=prices.length;
int ret=0;
for(int i=0;i<n;i++){
int j=i;
while(j+1<n && prices[j+1]>prices[j]){
j++;
}
ret+=prices[j]-prices[i];
i=j;
}
return ret;
}
}
按照一天一天的方式买
java
class Solution {
public int maxProfit(int[] prices) {
int n=prices.length;
int ret=0;
for(int i=1;i<n;i++){
if(prices[i]>prices[i-1]){
ret+=prices[i]-prices[i-1];
}
}
return ret;
}
}
k次取反后最大值的数组和
1005. K 次取反后最大化的数组和 - 力扣(LeetCode)

java
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
int m=0;
int minValue=Integer.MAX_VALUE;
int n=nums.length;
int ret=0;
for(int x:nums){
if(x<0){
m++;
}
minValue=Math.min(minValue,Math.abs(x));
}
if(m>k){
Arrays.sort(nums);
for(int i=0;i<k;i++){
ret+= -nums[i];
}
for(int i=k;i<n;i++){
ret += nums[i];
}
}
if(m==k){
for(int x:nums){
ret+=Math.abs(x);
}
}
if(m<k){
if((k-m)%2==0){
for(int x:nums){
ret+=Math.abs(x);
}
}else{
for(int x:nums){
ret+=Math.abs(x);
}
ret-=minValue*2;
}
}
return ret;
}
}
按身高排序

解法一:创建二元组
java
class Solution {
public String[] sortPeople(String[] names, int[] heights) {
int n=heights.length;
String[][] people=new String[n][2];
for(int i=0;i<n;i++){
people[i][0]=names[i];
people[i][1]=String.valueOf(heights[i]);
}
Arrays.sort(people,(a,b)->{
return Integer.parseInt(b[1])-Integer.parseInt(a[1]);
});
String[] ret=new String[n];
for(int i=0;i<n;i++){
ret[i]=people[i][0];
}
return ret;
}
}
解法二:Hash表的映射
java
class Solution {
public String[] sortPeople(String[] names, int[] heights) {
int n=heights.length;
Map<Integer,String> hash=new HashMap<>();
for(int i=0;i<n;i++){
hash.put(heights[i],names[i]);
}
Arrays.sort(heights);
String[] ret=new String[n];
for(int i=0;i<n;i++){
ret[i]=hash.get(heights[n-1-i]);
}
return ret;
}
}
解法三:把下标进行排序
java
class Solution {
public String[] sortPeople(String[] names, int[] heights) {
int n=heights.length;
Integer[] index=new Integer[n];
for(int i=0;i<n;i++){
index[i]=i;
}
Arrays.sort(index,(a,b)->{
return heights[b]-heights[a];
});
String[] ret=new String[n];
for(int i=0;i<n;i++){
ret[i]=names[index[i]];
}
return ret;
}
}
优势洗牌(田忌赛马)

java
class Solution {
public int[] advantageCount(int[] nums1, int[] nums2) {
int n=nums2.length;
Integer[] index=new Integer[n];
Arrays.sort(nums1);
for(int i=0;i<n;i++){
index[i]=i;
}
Arrays.sort(index,(a,b)->{
return nums2[a]-nums2[b];
});
int left=0;
int right=n-1;
int[] ret=new int[n];
for(int x:nums1){
if(x>nums2[index[left]]){
ret[index[left]]=x;
left++;
}else{
ret[index[right]]=x;
right--;
}
}
return ret;
}
}
最长回文串

java
class Solution {
public int longestPalindrome(String s) {
int[] hash=new int[127];
for(int i=0;i<s.length();i++){
hash[s.charAt(i)]++;
}
int ret=0;
for(int x:hash){
if(x%2==0){
ret+=x;
}else{
ret+=(x/2*2);
}
}
return ret<s.length()?ret+1:ret;
}
}
增减字符串匹配

当出现字符 I 放入最小值,当出现字符 D 放入最大值
java
class Solution {
public int[] diStringMatch(String s) {
int n=s.length();
int[] ret=new int[n+1];
int max=n;
int min=0;
for(int i=0;i<n;i++){
if(s.charAt(i)=='I'){
ret[i]=min;
min++;
}
if(s.charAt(i)=='D'){
ret[i]=max;
max--;
}
}
ret[n]=min;
return ret;
}
}
分发饼干

先将孩子和饼干升序
贪心策略:小孩子给小饼干
java
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int n=g.length;
int m=s.length;
int ret=0;
int i=0;
int j=0;
while(i<n && j<m){
if(g[i]<=s[j]){
ret++;
i++;
}
j++;
}
return ret;
}
}
双指针的写法:
java
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int n=g.length;
int m=s.length;
int ret=0;
// 双指针的写法
for(int i=0,j=0;i<n && j<m;i++,j++){
while(j<m && g[i]>s[j]){
j++;
}
if(j<m){
ret++;
}
}
return ret;
}
}
最优除法


java
class Solution {
public String optimalDivision(int[] nums) {
StringBuffer ret=new StringBuffer();
int n=nums.length;
if(n==1){
return ret.append(nums[0]).toString();
}
if(n==2){
return ret.append(nums[0]).append("/").append(nums[1]).toString();
}
if(n>=3){
ret.append(nums[0]).append("/(").append(nums[1]);
for(int i=2;i<n;i++){
ret.append("/").append(nums[i]);
}
ret.append(")");
}
return ret.toString();
}
}
跳跃游戏Ⅱ

java
class Solution {
public int jump(int[] nums) {
int left=0;
int right=0;
int n=nums.length;
int maxpos=0;
int ret=0;
while(left<=right){
if(maxpos>=n-1){
return ret;
}
for(int i=left;i<=right;i++){
maxpos=Math.max(maxpos,nums[i]+i);
}
left=right+1;
right=maxpos;
ret++;
}
return ret;
}
}
跳跃游戏

java
class Solution {
public boolean canJump(int[] nums) {
int left=0;
int right=0;
int n=nums.length;
int maxPos=0;
while(left<=right){
if(maxPos>=n-1){
return true;
}
for(int i=left;i<=right;i++){
maxPos=Math.max(maxPos,nums[i]+i);
}
left=right+1;
right=maxPos;
}
return false;
}
}
加油站

java
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n=gas.length;
for(int i=0;i<n;i++){
int rest=0;
int step=0;
for(;step<n;step++){
int index=(i+step)%n;
rest=rest+gas[index]-cost[index];
if(rest<0){
break;
}
}
if(rest>=0){
return i;
}
// 进行优化
i+=step;
}
return -1;
}
}
单调递增的数字

首先我们使用会超出时间限制的两种判断递增的方法
1.法一:
java
class Solution {
public int monotoneIncreasingDigits(int n) {
int prev=0;
int cur=0;
for(int i=n;i>0;i--){
if(judge(i))
return i;
}
return -1;
}
public boolean judge(int n){
int prev=0;
while(n>0){
prev=n%10;
int cur=n/10%10;
if(prev<cur){
return false;
}
prev=cur;
n/=10;
}
return true;
}
}
2.法二:
java
class Solution {
public int monotoneIncreasingDigits(int n) {
int prev=0;
int cur=0;
for(int i=n;i>0;i--){
if(judge(i))
return i;
}
return -1;
}
public boolean judge(int n){
char[] ch=String.valueOf(n).toCharArray();
int m=ch.length;
for(int i=m-2;i>=0;i--){
if(ch[i]>ch[i+1]){
return false;
}
}
return true;
}
}
正确的解法:贪心(找规律)
java
class Solution {
public int monotoneIncreasingDigits(int n) {
char[] s=String.valueOf(n).toCharArray();
int i=0;
int m=s.length;
while(i+1<m && s[i]<=s[i+1]){
i++;
}
if(i==m-1){
return n;
}
while(i-1>=0 && s[i]==s[i-1]){
i--;
}
s[i]--;
for(int j=i+1;j<m;j++){
s[j]='9';
}
return Integer.parseInt(new String(s));
}
}
坏了的计算器

反着来->(正难则反)
当target>start
target为偶数时 target/=2
为奇数时 target+=1
target<start
只能 target+=1
java
class Solution {
public int brokenCalc(int start, int target) {
int ret=0;
while(target!=start){
if(target>start){
if(target%2==0){
target/=2;
ret++;
}else{
target+=1;
ret++;
}
}else if(target<start){
target+=1;
ret++;
}
}
return ret;
}
}
合并区间

java
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals,(a,b)->{
return a[0]-b[0];
});
int left=intervals[0][0];
int right=intervals[0][1];
int n=intervals.length;
List<int[]> ret=new ArrayList<>();
for(int i=1;i<n;i++){
int a=intervals[i][0];
int b=intervals[i][1];
//可以合并
if(right>=a){
right=Math.max(right,b);
}else{//不能合并
ret.add(new int[]{left,right});
left=a;
right=b;
}
}
ret.add(new int[]{left,right});
return ret.toArray(new int[0][]);
}
}
无重叠区域

java
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals,(a,b)->{
return a[0]-b[0];
});
int ret=0;
int left=intervals[0][0];
int right=intervals[0][1];
for(int i=1;i<intervals.length;i++){
if(intervals[i][0]>=right){
// 无重叠区域,坐标相交不代表重叠
right=intervals[i][1];
}else{
right=Math.min(right,intervals[i][1]);
ret++;
}
}
return ret;
}
}
用最少数量的箭引爆气球
452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

java
class Solution {
public int findMinArrowShots(int[][] points) {
Arrays.sort(points,(a,b)->{
return a[0]>b[0]?1:-1;
});
int ret=1;
int left=points[0][0];
int right=points[0][1];
for(int i=1;i<points.length;i++){
if(right>=points[i][0]){
// 有重叠
right=Math.min(right,points[i][1]);
}else{
ret++;
right=points[i][1];
}
}
return ret;
}
}
整数替换

直接用递归
java
class Solution {
public int integerReplacement(int n) {
return dfs(n*1L);
}
public int dfs(long n){
if(n==1){
return 0;
}
if(n%2==0){
return 1+dfs(n/2);
}else{
return 1+Math.min(dfs(n+1),dfs(n-1));
}
}
}
优化成递归+记忆化搜索
java
class Solution {
Map<Long,Integer> ret;
public int integerReplacement(int n) {
ret=new HashMap<>();
return dfs(n*1L);
}
public int dfs(long n){
if(ret.containsKey(n)){
return ret.get(n);
}
if(n==1){
ret.put(n,0);
return ret.get(n);
}
if(n%2==0){
ret.put(n,1+dfs(n/2));
return ret.get(n);
}else{
ret.put(n,1+Math.min(dfs(n+1),dfs(n-1)));
return ret.get(n);
}
}
}
俄罗斯套娃信封问题

使用动态规划的方法会超出时间的限制

java
class Solution {
public int maxEnvelopes(int[][] envelopes) {
Arrays.sort(envelopes,(a,b)->{
return a[0]-b[0];
});
int n=envelopes.length;
int[] dp=new int[n];
int ret=1;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(envelopes[i][0]>envelopes[j][0] && envelopes[i][1]>envelopes[j][1]){
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
ret=Math.max(ret,dp[i]);
}
return ret;
}
}
重写排序+贪心+二分(⭐)
java
class Solution {
public int maxEnvelopes(int[][] e) {
Arrays.sort(e, (v1, v2) -> {
return v1[0] != v2[0] ? v1[0] - v2[0] : v2[1] - v1[1];
});
ArrayList<Integer> ret = new ArrayList<>();
ret.add(e[0][1]);
for(int i = 1; i < e.length; i++){
int b = e[i][1];
if(b > ret.get(ret.size() - 1)){
ret.add(b);
}
else {
int left = 0, right = ret.size() - 1;
while(left < right)
{
int mid = (left + right) / 2;
if(ret.get(mid) >= b) right = mid;
else left = mid + 1;
}
ret.set(left, b);
}
}
return ret.size();
}
}