LeetCode 668. 乘法表中第k小的数 / 462. 最少移动次数使数组元素相等 II / 436. 寻找右区间
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 668. 乘法表中第k小的数 / 462. 最少移动次数使数组元素相等 II / 436. 寻找右区间相关的知识,希望对你有一定的参考价值。
668. 乘法表中第k小的数
2022.5.18 每日一题
题目描述
几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第k小的数字吗?
给定高度m 、宽度n 的一张 m * n的乘法表,以及正整数k,你需要返回表中第k 小的数字。
例 1:
输入: m = 3, n = 3, k = 5
输出: 3
解释:
乘法表:
1 2 3
2 4 6
3 6 9
第5小的数字是 3 (1, 2, 2, 3, 3).
例 2:
输入: m = 2, n = 3, k = 6
输出: 6
解释:
乘法表:
1 2 3
2 4 6
第6小的数字是 6 (1, 2, 2, 3, 4, 6).
注意:
m 和 n 的范围在 [1, 30000] 之间。
k 的范围在 [1, m * n] 之间。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/kth-smallest-number-in-multiplication-table
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
需要想到将问题转换为找小于或大于某个数的数字个数,就有思路了
官解又将中间统计个数的式子简化了一下
当i<=x/n时,这几行的所有数都算,所以有前半部分的式子
后半部分就是正常的
class Solution
public int findKthNumber(int m, int n, int k)
//左上角小于右下角,暴力过不了只能考虑二分啥的
//能不能直接计算小于某个数的个数或者大于某个数的个数,好像是可以的
//比如对于一个数x,小于它的数可以遍历每一行计算
//然后二分找第k小就行了
int left = 1;
int right = m * n;
while(left < right)
int mid = (right - left) / 2 + left;
//找小于等于num的个数
int num = 0;
for(int i = 1; i <= m; i++)
int t = mid / i;
num += n < t ? n : t;
if(num < k)
left = mid + 1;
else
right = mid;
return left;
462. 最少移动次数使数组元素相等 II
2022.5.19 每日一题
题目描述
给你一个长度为 n 的整数数组 nums ,返回使所有数组元素相等需要的最少移动数。
在一步操作中,你可以使数组中的一个元素加 1 或者减 1 。
示例 1:
输入:nums = [1,2,3]
输出:2
解释:
只需要两步操作(每步操作指南使一个元素加 1 或减 1):
[1,2,3] => [2,2,3] => [2,2,2]
示例 2:
输入:nums = [1,10,2,9]
输出:16
提示:
n == nums.length
1 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-moves-to-equal-array-elements-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
刚开始想着平均数应该就是最小移动次数的,写了如下代码,结果被1 0 0 8 6这个例子教育了
class Solution
public int minMoves2(int[] nums)
//到达平均数,移动数最少,四舍五入取最接近的平均数
int l = nums.length;
long sum = 0;
for(int n : nums)
sum += n;
long ave1 = sum / l;
long ave2 = ave1 + 1;
long step1 = 0, step2 = 0;
for(int n : nums)
step1 += Math.abs(ave1 - n);
step2 += Math.abs(ave2 - n);
return (int)Math.min(step1, step2);
然后想了一下众数,很明显有反例,又试了一下中位数,过了
为什么是中位数呢,因为在排序以后,将前后两个数两两配对,如nums[0]和nums[n-1],nums[1]和nums[n-2],可以发现,要想使得移动次数最小,当这个数取最中间的数时,左边的数变成这个数要加,右边的数变成这个数要减,即每一个区间移动的次数都是区间上限减下限(就两个数,就是大减小);而如果取中间左边的数ll,那么,有的区间就会都是大于ll,那么移动的次数肯定是大于上限减下限,取右边的数rr同理
因此直接取中位数最优
class Solution
public int minMoves2(int[] nums)
//那到底怎么移动是最小的呢,难道是移动到中位数吗
int l = nums.length;
Arrays.sort(nums);
int mid = nums[l / 2];
long step = 0;
for(int n : nums)
step += Math.abs(mid - n);
return (int)step;
436. 寻找右区间
2022.5.20 每日一题
题目描述
给你一个区间数组 intervals ,其中 intervals[i] = [starti, endi] ,且每个 starti 都 不同 。
区间 i 的 右侧区间 可以记作区间 j ,并满足 startj >= endi ,且 startj 最小化 。
返回一个由每个区间 i 的 右侧区间 的最小起始位置组成的数组。如果某个区间 i 不存在对应的 右侧区间 ,则下标 i 处的值设为 -1 。
示例 1:
输入:intervals = [[1,2]]
输出:[-1]
解释:集合中只有一个区间,所以输出-1。
示例 2:
输入:intervals = [[3,4],[2,3],[1,2]]
输出:[-1,0,1]
解释:对于 [3,4] ,没有满足条件的“右侧”区间。
对于 [2,3] ,区间[3,4]具有最小的“右”起点;
对于 [1,2] ,区间[2,3]具有最小的“右”起点。
示例 3:
输入:intervals = [[1,4],[2,3],[3,4]]
输出:[-1,2,-1]
解释:对于区间 [1,4] 和 [3,4] ,没有满足条件的“右侧”区间。
对于 [2,3] ,区间 [3,4] 有最小的“右”起点。
提示:
1 <= intervals.length <= 2 * 10^4
intervals[i].length == 2
-10^6 <= starti <= endi <= 10^6
每个间隔的起点都 不相同
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-right-interval
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
哈希表,排序+二分
class Solution
public int[] findRightInterval(int[][] intervals)
//哈希表存,然后排序就行了二分找就行了
int l = intervals.length;
List<int[]> list = new ArrayList<>();
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < l; i++)
list.add(new int[]intervals[i][0], i);
map.put(intervals[i][0], i);
Collections.sort(list, (a, b) -> (a[0] - b[0]));
int[] res = new int[l];
for(int i = 0; i < l; i++)
int[] temp = intervals[i];
int end = temp[1];
//找比end大的第一个数
int left = 0;
int right = l;
while(left < right)
int mid = (right - left) / 2 + left;
if(list.get(mid)[0] < end)
left = mid + 1;
else
right = mid;
if(left == l)
res[i] = -1;
else
res[i] = map.get(list.get(left)[0]);
return res;
以上是关于LeetCode 668. 乘法表中第k小的数 / 462. 最少移动次数使数组元素相等 II / 436. 寻找右区间的主要内容,如果未能解决你的问题,请参考以下文章
[Leetcode]668.Kth Smallest Number in Multiplication Table