刷题日记 - 2 记录刷题。
难度:简单
1 2 3 4 5 6 7 8 9 10 11 class Solution { public int maxProfit (int [] prices) { int res = 0 ; int min = Integer.MAX_VALUE; for (int n : prices){ min = Math.min(min,n); res = Math.max(res,n - min); } return res; } }
遍历整个数组中的数,遍历时记录当前数之前的最小值,计算在当天卖出的最大可能利润。比较每一天的最大可能利润,留下最大的值。
难度:中等
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution { public int maxProfit (int [] prices) { int len = prices.length; if (len<2 ) return 0 ; int [][] dp = new int [len][2 ]; 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 ]; } }
定义状态:
dp[i][0]
:第i
天手上未持股的最大余额
dp[i][1]
:第i
天手上持股的最大余额
状态转移方程:
dp[i][0] = max(dp[i-1][0],dp[i-1][1]+price[i])
:当天不持股的最大余额,取决于前一天持股的最大余额+当天股票价格(当天卖出),和前一天不持股最大余额(今天也不买入)
dp[i][1] = max(dp[i-1][1],dp[i-1][0]-price[i])
:当天持股的最大余额,取决于前一天不持股-当天股票价格(当天买入),和前一天持股最大余额(今天不卖出)
过去n
天后,最大的利润一定是第n
天不持股的最大余额。
抽象成dp状态有点困难。
贪心解法,对于今天减去昨天的股价,所得的数有三种可能,负数、零、正数;只在结果上加上正数,局部最优。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public int maxProfit (int [] prices) { int len = prices.length; int res = 0 ; if (len<2 )return 0 ; for (int i=1 ;i<len;i++){ int diff = prices[i] - prices[i-1 ]; if (diff>0 ){ res += diff; } } return res; } }
难度:中等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int hIndex (int [] citations) { int len = citations.length; int [] count = new int [1001 ]; for (int citation:citations){ for (int i=citation;i>=0 ;i--){ count[i]++; } } int res = 1000 ; for (;res>=0 ;res--){ if (count[res]>=res) return res; } return res; } }
计数排序
定义count[i] = j
代表引用次数大于等于i
的文章有j
篇,然后h指数从高向低依次遍历即可。
难度:中等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import java.util.HashMap;import java.util.Random;class RandomizedSet { Random random; HashMap<Integer, Integer> map; int [] nums; int idx; public RandomizedSet () { random = new Random (); map = new HashMap <>(); nums = new int [200001 ]; idx = -1 ; } public boolean insert (int val) { if (map.containsKey(val)){ return false ; } else { nums[++idx] = val; map.put(val, idx); return true ; } } public boolean remove (int val) { if (map.containsKey(val)){ int valIdx = map.get(val); map.remove(val); nums[valIdx] = nums[idx]; if (idx != valIdx){ map.put(nums[idx], valIdx); } idx--; return true ; } else { return false ; } } public int getRandom () { return nums[random.nextInt(idx + 1 )]; } }
插入和删除都要时间复杂度为O(1) –> 哈希表
随机取值 –> 数组
哈希表和数组连接 –> key为实际的值,value为实际值对应的数组下标
手动维护数组前idx
个元素不为空
难度:中等
暴力解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public int canCompleteCircuit (int [] gas, int [] cost) { for (int i=0 ;i<gas.length;i++){ if (gas[i]>=cost[i]){ if (i==fun(gas,cost,i)){ return i; } } } return -1 ; } private int fun (int [] gas,int [] cost,int start) { int len = gas.length; int pos = start; int curGas = gas[pos]; int nextPos = (pos+1 )%len; while (curGas>=cost[pos]){ curGas = curGas - cost[pos]+ gas[nextPos]; pos = nextPos; nextPos = (pos+1 )%len; if (pos==start)break ; } return pos; }; }
超出时间限制了。
优化点:
如果从第i
个出发只能到达第j
个加油站,那么从第i
个到第j
个加油站出发都不能环绕一圈。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public int canCompleteCircuit (int [] gas, int [] cost) { for (int i=0 ;i<gas.length;i++){ if (gas[i]>=cost[i]){ int end = fun(gas,cost,i); if (i == end){ return i; }else if (end<i){ return -1 ; }else { i = end; } } } return -1 ; } private int fun (int [] gas,int [] cost,int start) { int len = gas.length; int pos = start; int curGas = gas[pos]; int nextPos = (pos+1 )%len; while (curGas>=cost[pos]){ curGas = curGas - cost[pos]+ gas[nextPos]; pos = nextPos; nextPos = (pos+1 )%len; if (pos==start)break ; } return pos; }; }
难度:困难
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public int candy (int [] ratings) { int len = ratings.length; int [] candies = new int [len]; Arrays.fill(candies, 1 ); if (len < 2 ) return len; for (int i = 1 ; i < len; i++) { if (ratings[i] > ratings[i - 1 ]) { candies[i] = candies[i - 1 ] + 1 ; } } for (int j = len - 2 ; j >= 0 ; j--) { if (ratings[j] > ratings[j + 1 ]) { candies[j] = Math.max(candies[j + 1 ] + 1 , candies[j]); } } int res = 0 ; for (int candy : candies) { res += candy; } return res; } }
从左到右遍历 :
for(int i=1; i<len; i++)
:从第二个孩子开始遍历。
if(ratings[i] > ratings[i-1])
:如果当前孩子的评分高于前一个孩子,则当前孩子的糖果数比前一个孩子多1 。
从右到左遍历 :
for(int j=len-2; j>=0; j--)
:从倒数第二个孩子开始遍历。
if(ratings[j] > ratings[j+1])
:如果当前孩子的评分高于后一个孩子,则当前孩子的糖果数需要确保比后一个孩子多1 。
candies[j] = Math.max(candies[j+1] + 1, candies[j]);
:确保当前孩子的糖果数既满足从右到左的要求,也不小于从左到右遍历时已经分配的糖果数。