重刷LeetCode-数组
更新记录
时间 | 记录(更新题号) |
---|---|
2020年8月11日 | 1480. 一维数组的动态和 1431. 拥有最多糖果的孩子 1512. 好数对的数目 |
2020年8月12日 | 1470. 重新排列数组 1486. 数组异或操作 1313. 解压缩编码列表 |
2020年8月18日 | 26. 删除排序数组中的重复项【简单】 1395. 统计作战单位数【中等】 |
2020年8月22日 | 35. 搜索插入位置【简单】 121. 买卖股票的最佳时机【简单】 27. 移除元素【简单】 |
2020年9月6日 | 4. 寻找两个正序数组的中位数【困难】 |
1480. 一维数组的动态和
(1)题目描述
给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。
请返回 nums 的动态和。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/running-sum-of-1d-array
(2)解法与思路
很简单。
class Solution {
public int[] runningSum(int[] nums) {
int[] res = new int[nums.length];
if(nums.length == 0) {
return res;
}
res[0] = nums[0];
for(int i = 1; i < nums.length; i++) {
res[i] = nums[i] + res[i-1];
}
return res;
}
}
1431. 拥有最多糖果的孩子
(1)题目描述
给你一个数组 candies 和一个整数 extraCandies ,其中 candies[i] 代表第 i 个孩子拥有的糖果数目。
对每一个孩子,检查是否存在一种方案,将额外的 extraCandies 个糖果分配给孩子们之后,此孩子有 最多 的糖果。注意,允许有多个孩子同时拥有 最多 的糖果数目。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kids-with-the-greatest-number-of-candies
(2)解法与思路
也很简单。
class Solution {
public List<Boolean> kidsWithCandies(int[] candies, int extraCandies) {
List<Boolean> res = new ArrayList<Boolean>();
int num = candies.length;
if(num == 0) {
return res;
}
int max = candies[0];
for(int i = 1; i < num; i++) {
if(candies[i] > max) {
max = candies[i];
}
}
for(int i = 0; i < num; i++) {
if(candies[i] + extraCandies >= max) {
res.add(true);
}
else {
res.add(false);
}
}
return res;
}
}
1512. 好数对的数目
(1)题目描述
给你一个整数数组 nums 。
如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组 好数对 。
返回好数对的数目。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-good-pairs
(2)思路与解法
解法一:暴力求解,,枚举所有的数对。
class Solution {
public int numIdenticalPairs(int[] nums) {
int res = 0;
int len = nums.length;
if(len <= 1) {
return 0;
}
for(int i = 0; i < len; i++) {
for(int j = i+1; j < len; j++) {
if(nums[i] == nums[j]) {
res++;
}
}
}
return res;
}
}
解法二:组合的方法。统计数组中每个数字出现的次数,假设一个数字M出现了n次,那么总共有n*(n-1)/2个好数对。用哈希表。
class Solution {
public int numIdenticalPairs(int[] nums) {
int res = 0;
int len = nums.length;
if(len <= 1) {
return 0;
}
Map<Integer, Integer> m = new HashMap<Integer, Integer>();
for(int i = 0; i < len; i++) {
m.put(nums[i], m.getOrDefault(nums[i], 0)+1);
}
for (Map.Entry<Integer, Integer> entry : m.entrySet()) {
int v = entry.getValue();
res += v * (v - 1) / 2;
}
return res;
}
}
(3)补充知识
1.Map.getOrDefault(Object key, V defaultValue)方法
当Map集合中有这个key时,就使用这个key值;
如果没有就使用默认值defaultValue。
2.for(Map.Entry<Integer, Integer> entry : m.entrySet()){}
是一种常见的哈希表的遍历方法,entrySet是 java中 键-值 对的集合。遍历方法可以参考下面的博客:
1470. 重新排列数组
给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,…,xn,y1,y2,…,yn] 的格式排列。
请你将数组按 [x1,y1,x2,y2,…,xn,yn] 格式重新排列,返回重排后的数组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shuffle-the-array
(1)题目描述
(2)解法与思路
解法一:遍历,找规律
class Solution {
public int[] shuffle(int[] nums, int n) {
int[] res = new int[2*n];
int index = 0;
for(int i = 0 ; i < n; i++) {
res[index++] = nums[i];
res[index++] = nums[i+n];
}
return res;
}
}
解法二:先找规律,以[0,1,2,3,4,5,6,7],转换后的是[0,4,1,5,2,8,3,7]
i=0 ->0
i=1 ->2
i=2 ->4
i=3 ->6
i=4 ->1
i=5 ->3
i=6 ->5
i=7 ->7
可以推导出:i < n时,第i位的数将会转到2*i处;i > n时,第i位的数将会转到(i-n)*2+1
又有题目中提到,数组中每个数是大于0的,可以用复数来标记是否已经移动到正确的位置。
PS : 这种解法需要满足在任意位置开始,都可以得到一个环。。。这个咋证一下呢?
class Solution {
public int[] shuffle(int[] nums, int n) {
for(int i = 0; i < 2 * n; i++) {
int j = i;
while (nums[i] >= 0) {
j = getNewSite(j, n);
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = -tmp;
}
}
for(int i = 0; i < 2*n; i++) {
if(nums[i] < 0) {
nums[i] = -nums[i];
}
}
return nums;
}
public int getNewSite(int oldSite, int n) {
if(oldSite < n) {
return oldSite*2;
}
else {
return (oldSite - n) * 2 + 1;
}
}
}
(3)补充知识
老生常谈的i++和++i:
i++ 先赋值在运算,例如 a=i++,先赋值a=i,后运算i=i+1,所以结果是a=1
++i 先运算在赋值,例如 a=++i,先运算i=i+1,后赋值a=i,所以结果是a=2
1486. 数组异或操作
(1)题目描述
给你两个整数,n 和 start 。
数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。
请返回 nums 中所有元素按位异或(XOR)后得到的结果。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xor-operation-in-an-array
(2)思路与解法
暴力求解:
class Solution {
public int xorOperation(int n, int start) {
int res = start;
for(int i = 1; i < n; i++) {
res = res ^ (start + i * 2);
}
return res;
}
}
1313. 解压缩编码列表
(1)题目描述
给你一个以行程长度编码压缩的整数列表 nums 。
考虑每对相邻的两个元素 [freq, val] = [nums[2i], nums[2i+1]] (其中 i >= 0 ),每一对都表示解压后子列表中有 freq 个值为 val 的元素,你需要从左到右连接所有子列表以生成解压后的列表。
请你返回解压后的列表。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decompress-run-length-encoded-list
(2)思路与解法
暴力求解,先算出目标数组的长度,再遍历原来的数组,向新数组中填充数字。
class Solution {
public int[] decompressRLElist(int[] nums) {
int size = 0;
for(int i = 0; i < nums.length; i = i + 2) {
size += nums[i];
}
int[] res = new int[size];
int temp = 0;
for(int i = 0; i < nums.length; i = i + 2) {
for(int j = 0; j < nums[i]; j++) {
res[temp] = nums[i+1];
temp++;
}
}
return res;
}
}
26. 删除排序数组中的重复项
(1)题目描述
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array
(2)思路与解法
双指针,一个去遍历,另一个去标记修改后的位置。
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length == 0) {
return 0;
}
if(nums.length == 1) {
return 1;
}
int i = 1, j = 0;
for(; i < nums.length && j < nums.length; i++) {
if(nums[i] != nums[j]) {
j++;
nums[j] = nums[i];
}
}
return j+1;
}
}
1395. 统计作战单位数
(1)题目描述
n 名士兵站成一排。每个士兵都有一个 独一无二 的评分 rating 。
每 3 个士兵可以组成一个作战单位,分组规则如下:
从队伍中选出下标分别为 i、j、k 的 3 名士兵,他们的评分分别为 rating[i]、rating[j]、rating[k]
作战单位需满足: rating[i] < rating[j] < rating[k] 或者 rating[i] > rating[j] > rating[k] ,其中 0 <= i < j < k < n
请你返回按上述条件可以组建的作战单位数量。每个士兵都可以是多个作战单位的一部分。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-teams
(2)思路与解法
解法一:暴力求解,用三个指针去标记,遍历整个数组。
class Solution {
public int numTeams(int[] rating) {
if(rating.length < 3) {
return 0;
}
int n = rating.length;
int res = 0;
for(int i = 0, j = 1, k = 2; i < n; k++) {
//System.out.println(i + " " + j + " " + k);
if(k == n) {
if(j != n - 2) {
j++;
k = j + 1;
}
else {
if(i != n - 3) {
i++;
}
else {
break;
}
j = i + 1;
k = j + 1;
}
}
if((rating[i] > rating[j] && rating[j] > rating[k]) || (rating[i] < rating[j] && rating[j] < rating[k])) {
res++;
}
}
return res;
}
}
解法二:统计每个中间士兵左边和右边满足条件的士兵:左边比他小的人数 × 右边比他大的人数 + 左边比他大的人数 × 右边比他小的人数。
class Solution {
public int numTeams(int[] rating) {
int n = rating.length;
int res = 0;
for (int i = 1; i < n - 1; ++i) {
int[] left = count(rating, 0, i, rating[i]);
int[] right = count(rating, i, n, rating[i]);
res += left[0] * right[1] + left[1] * right[0];
}
return res;
}
private int[] count(int[] rating, int from, int to, int key) {
int[] results = new int[2];
for (int i = from; i < to; ++i) {
if (rating[i] < key) {
++results[0];
} else if (rating[i] > key) {
++results[1];
}
}
return results;
}
}
35. 搜索插入位置
(1)题目描述
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-teams
(2)思路与解法
class Solution {
public int searchInsert(int[] nums, int target) {
int i = 0;
for(; i < nums.length; i++) {
if(nums[i] == target) {
return i;
}
else if(nums[i] > target) {
break;
}
}
return i;
}
}
121. 买卖股票的最佳时机
(1)题目描述
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
(2)思路与解法
解法一:暴力求解
class Solution {
public int maxProfit(int[] prices) {
if(prices.length <= 1) {
return 0;
}
int[] tem = new int[prices.length];
for(int i = 0; i < prices.length; i++) {
int res = 0;
for(int j = i + 1; j < prices.length; j++) {
if(prices[j] - prices[i] > res) {
res = prices[j] - prices[i];
}
}
tem[i] = res;
}
Arrays.sort(tem);
return tem[tem.length-1];
}
}
解法二:用一个变量去记录最低价,并计算今天卖出可以挣到的钱。
class Solution {
public int maxProfit(int[] prices) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice)
minprice = prices[i];
else if (prices[i] - minprice > maxprofit)
maxprofit = prices[i] - minprice;
}
return maxprofit;
}
}
27. 移除元素
(1)题目描述
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-element
(2)思路与解法
用两个指针遍历,发现目标值时,只有i++,j不动,记录下这个位置。
class Solution {
public int removeElement(int[] nums, int val) {
int i = 0, j = 0;
for(; i < nums.length && j < nums.length; i++) {
//System.out.println(i + " " + j);
if(nums[i] != val) {
nums[j] = nums[i];
j++;
}
}
return j;
}
}
4. 寻找两个正序数组的中位数
(1)题目描述
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
(2)思路与解法
解法一:用双指针,分别遍历两个数组,遍历时比较当前值得大小,最后得到排序在中间的两个数。…这个题隔了两周了,之前写了一半的代码就没改。开始是没有区分这个中位数是否可以直接获取还是要除以2(数组长度为奇数可以去直接取中间的那个数,为偶数就是要除以2),因此标记了两个相邻大小的数字,最后再去叛变中位数的值…代码写的就有点乱了…
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int i = 0, j = 0, target1 = Integer.MIN_VALUE, target2 = Integer.MIN_VALUE;
while(i + j < (len1 + len2)/2 + 1) {
if(j == len2 || (i < len1 && nums1[i] < nums2[j])) {
if(target1 < target2) {
target1 = nums1[i];
}
else {
target2 = nums1[i];
}
i++;
}
else{
if(target1 < target2) {
target1 = nums2[j];
}
else {
target2 = nums2[j];
}
j++;
}
}
if((len1 + len2)%2 == 0) {
return (target1 + target2)/2.0;
}
double result = target1 > target2 ? target1/1.0 : target2/1.0;
return result;
}
}
解法二、三:上面那个解法时间复杂度是m+n,达不到log(m+n),可以考虑二分查找,代码还没写,贴一下LeetCode上大神们的思路和解法好了