剑指 Offer 03. 数组中重复的数字(简单)
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
1.哈希表
class Solution {
public int findRepeatNumber(int[] nums) {
Map<Integer,Integer> map=new HashMap<>();
for(int num:nums){
if(map.containsKey(num))return num;
else map.put(num,1);
}
return -1;
}
}
2.原地置换(用数组构建哈希表)
class Solution {
public int findRepeatNumber(int[] nums) {
boolean[] bool = new boolean[nums.length];
for(int i=0;i<nums.length;i++){
if(bool[nums[i]]==true){
return nums[i];
}
bool[nums[i]]=true;
}
return -1;
}
}
剑指 Offer 66. 构建乘积数组(中等)
给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
示例:
输入: [1,2,3,4,5]
输出: [120,60,40,30,24]
模拟,找规律
细画一下可以发现,能够分为上下三角,B数组先A数组走一步即可
先计算下三角(左边),
再计算上三角(右边),并累积左边的
class Solution {
public int[] constructArr(int[] a) {
//每次res都先行一步
int[] res=new int[a.length];
int tmp1=1;
int tmp2=1;
for(int i=0;i<a.length;i++){
res[i]=tmp1;//计算左边
tmp1=tmp1*a[i];
}
for(int i=a.length-1;i>=0;i--){
res[i]*=tmp2;//计算右边,并累积左边
tmp2=tmp2*a[i];
}
return res;
}
}
135. 分发糖果(困难)
n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。示例 1:
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。
贪心算法:
先给每个人一颗糖,满足条件1
对于条件2:
左贪心:从左往右,遇到比前一个大的就在前一个基础上加1
右贪心:再从右到左,同理
最后取两边都满足的值(即最大值,为什么是最大值可以自己假设推一下,不难)
class Solution {
public int candy(int[] ratings) {
int[] left=new int[ratings.length];
int[] right=new int[ratings.length];
Arrays.fill(left,1);
Arrays.fill(right,1);
for(int i=1;i<ratings.length;i++){
if(ratings[i]>ratings[i-1])left[i]=left[i-1]+1;
}
int count=left[left.length-1];
for(int i=ratings.length-2;i>=0;i--){
if(ratings[i]>ratings[i+1])right[i]=right[i+1]+1;
count+=Math.max(left[i],right[i]);
}
return count;
}
}
空间遍历(空间复杂度低,效率优于贪心):
从左边开始,初始化四个变量:计数器count,当前同学糖果pre,升序长度,降序长度。
为什么要计算升序和降序长度呢?
(无论升序还是降序,当前序列长度都和某一同学最大糖果数相同)
当升序与降序长度相同时会出现特殊情况:降序中的第一个糖果数(降序中最大的)会与升序的最后一个糖果数相等(升序中最大的),这个时候就需要将升序的最后一个并入降序(不能将降序并入升序,不合规则),并入的操作其实很简单,糖果总数加1即可,这个1就是补给升序的最后一个的,方便它能并入降序(使得升序最后一个大于降序的第一个)。
class Solution {
public int candy(int[] ratings) {
//计数器
int count=1;
//当前同学糖果,升序长度,降序长度
int pre=1,asc=1,dec=0;
for(int i=1;i<ratings.length;i++){
if(ratings[i]>=ratings[i-1]){
dec=0;//升序
pre=ratings[i]==ratings[i-1]?1:pre+1;//遇到相等的,多给一个即可
count+=pre;//计数
asc=pre;//更新升序长度
}else{
dec++;//降序,这个相当与之前已经分配糖果的同学向后平移,而不是越往后越多
if(dec==asc)dec++;//当降序长度与升序长度相同时,将升序最后一个并入降序
count+=dec;//计数
pre=1;//更新当前同学的糖果数
}
}
return count;
}
}
链接:https://leetcode-cn.com/
来源:力扣(LeetCode)