一、LeetCode第845题.数组中的最长山脉
845.数组中的最长山脉
遍历A,利用两个数组分别记录从左边到每个元素的上升子数组长度和从该元素往右的下降子数组长度,若A[i]对应的两个数组的值都大于零,则A[i]可以为山顶,以A[i]为山顶的山脉长度等于两个数组对应元素之和加1,这个1代表A[i]本身,即left[i] + right[i] + 1。遍历区其最大值即可
class Solution {
public int longestMountain(int[] A) {
int n = A.length;
int[] left = new int[n]; //记录从左边到该元素的上升子数组长度
int[] right = new int[n]; //记录从该元素往右的下降子数组长度
for(int i=1; i < n; ++i){
if(A[i] > A[i-1]){
left[i] = left[i-1] + 1;
}
if(A[n-i-1] > A[n-i]){
right[n-i-1] = right[n-i] + 1;
}
}
int max1 = 0;
for(int i=0; i < n; ++i){ //遍历取最大值
if(left[i] != 0 && right[i] != 0){ //满足条件则A[i]可作为山顶
max1 = left[i] + right[i] + 1 > max1?left[i] + right[i] + 1:max1;
}
}
return max1;
}
}
还有一种方法是模拟上下山:记录左边山脚即山峰开始的位置,通过一个变量明确正在进行的状态是上山、下山和没在山上,通过在遍历中根据A数组相邻元素的大小关系不断更变状态来更新山峰的最大长度。边缘条件:若最后是在下山状态结束的遍历,则最后一次山峰的长度在遍历中并没有计算,所以要在遍历完成后进行判断
class Solution {
public int longestMountain(int[] A) {
int max = 0,left = 0; //left记录左边山脚位置
int t = 0; //t记录模拟状态,t = 0:没在山上,t = 1:上山,t = 2:下山
for(int i = 1; i < A.length; i++){
if(A[i] > A[i-1]){ //满足上山条件
if(t == 0){ //没在山上且满足上山条件
t = 1; //更变状态为上山
left = i; //记录左山脚位置
}else if(t == 2){ //下山时不满足继续下山条件
max = i - left> max?i -left:max; //计算本山峰长度并更新最长山峰长度
t = 1; //满足上山条件,更变状态为上山
left = i; //记录左山脚位置
}
}else if(A[i] < A[i-1]){ //满足下山条件
if(t == 1){ //上山中满足下山条件
t = 2; //更变状态为下山
}
}else{
if(t == 1){ //上山时走平路,即不在山上
t = 0; //更新状态为不在山上
}else if(t == 2){ //下山时走平路,即已经下山
max = i - left > max?i -left:max;//计算本山峰长度并更新最长山峰长度
t = 0; //更新状态为不在山上
}
}
}
if(t == 2){ //遍历以下山结束
max = A.length - left > max?A.length - left:max;//计算最后一个山峰长度,并更新最长山峰长度
}
return max != 0?max + 1:0;
}
}
二、LeetCode第948题.令牌放置
贪心:在让令牌正面朝上的时候,即用能量换分数时,肯定要去找能量最小的令牌。同样的,在让令牌反面朝上的时候,即用分数换能量时,肯定要去找能量最大的令牌。值得注意的是剩下最后一个令牌时,如果不能用其换取分数,那么就能不必使用分数换取其能量。
class Solution {
public int bagOfTokensScore(int[] tokens, int P) {
int len = tokens.length - 1;
Arrays.sort(tokens); //对令牌能量升序排序
int i = 0,sum = 0;
while(i <= len ){ //尽量先用令牌换取分数
if(P >= tokens[i]){
P -= tokens[i];
i++;
sum++;
}else if(sum > 0){ //剩余能量不足以换取分数且分数大于零
if(i==len){ //最后一个令牌不能换分数则输出当前分数
return sum;
}
P += tokens[len];
len--;
sum--;
}else{
return sum;
}
}
return sum;
}
}
三、LeetCode第1207题.独一无二的出现次数
1207.独一无二的出现次数
哈希表:遍历一遍arr[]数组,因其值可以为负数,且区间已知,故可以arr[i]+1000作为哈希表数组的下标,统计每个数出现的次数。
每个数出现的次数已知可以再次遍历记录出现次数的数组,用同样的方式记录同一个出现次数出现的次数,若相同的出现次数(零除外)出现两次则说明出现次数不是独一无二的。
class Solution {
public boolean uniqueOccurrences(int[] arr) {
int[] count = new int[2001]; //用来记录每个数字出现的次数
for(int i=0; i<arr.length; ++i){
count[arr[i]+1000]++; //因为-1000<=arr[i],因此使arr[i]+1000作为下标,使下标满足大于等于0
}
int[] sum = new int[1000]; //用来记录数字出现次数的出现次数
for(int i=0; i < 2001; ++i){
if(count[i] != 0){
sum[count[i]]++;
if(sum[count[i]] > 1){ //如果同一个出现次数出现两次则返回false
return false;
}
}
}
return true;
}
}
统计每个数出现次数之后还可以这样:先对统计次数的数组进行排序,然后遍历这个数组,如果其某个元素的值不为0且与之后的元素相等,则说明该出现次数不是独一无二的,返回false。该方法的执行速度较慢
Arrays.sort(count);
for(int i = 0; i < 2000; i++){
if(count[i] != 0 && count[i] == count[i+1]){
return false;
}
}
return true;