一、
难度中等203
给你一个整数数组 nums
。每次 move 操作将会选择任意一个满足 0 <= i < nums.length
的下标 i
,并将 nums[i]
递增 1
。
返回使 nums
中的每个值都变成唯一的所需要的最少操作次数。
示例 1:
输入:nums = [1,2,2] 输出:1 解释:经过一次 move 操作,数组将变为 [1, 2, 3]。
示例 2:
输入:nums = [3,2,1,2,1,7] 输出:6 解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。 可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。
三种方法解题:
第一种排序法:
略
第二种计数法:
计算每个数字出现次数,再便利往后推即可
class Solution {
public:
int minIncrementForUnique(vector<int>& nums) {
vector<int>a(400001,0);
int Max=0;
int move=0;
for(int i=0;i<nums.size();i++)
{
Max=max(Max,nums[i]);
a[nums[i]]++;
}
for(int i=0;i<=Max;i++)
{
if(a[i]>1)
{
int t=a[i]-1;
move+=t;
a[i+1]+=t;
}
}
int d=a[Max+1]-1;
move+=d*(1+d)/2;
return move;
}
};
***********第三种线性探测法:(未学没搞太懂)
class Solution {
int[] pos = new int [80000];
public int minIncrementForUnique(int[] A) {
Arrays.fill(pos, -1); // -1表示空位
int move = 0;
// 遍历每个数字a对其寻地址得到位置b, b比a的增量就是操作数。
for (int a: A) {
int b = findPos(a);
move += b - a;
}
return move;
}
// 线性探测寻址(含路径压缩)
private int findPos(int a) {
int b = pos[a];
// 如果a对应的位置pos[a]是空位,直接放入即可。
if (b == -1) {
pos[a] = a;
return a;
}
// 否则向后寻址
// 因为pos[a]中标记了上次寻址得到的空位,因此从pos[a]+1开始寻址就行了(不需要从a+1开始)。
b = findPos(b + 1);
pos[a] = b; // 寻址后的新空位要重新赋值给pos[a]哦,路径压缩就是体现在这里。
return b;
}
}
---------------------------------------------------------------------------------------------------------------------------------
二、
难度中等354收藏分享切换为英文接收动态反馈
给定一个包含非负整数的数组 nums
,返回其中可以组成三角形三条边的三元组个数。
示例 1:
输入: nums = [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3
示例 2:
输入: nums = [4,2,3,4] 输出: 4
思路:先排序,然后使用找最后一个在有序数组中小于nums[i] + nums[j]的数的下标,与j相减就可以得到nums[i] 和nums[j]为小两边的情况下的配对情况;k值的设立:记录最后一个小于nums[i] + nums[j]的数,防止与nums[i] + nums[j]相等
class Solution {
public:
int triangleNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
int i,j;
int num=0;
for(i=0;i<nums.size();i++)
{
for(j=i+1;j<nums.size();j++)
{
int left = j + 1, right = nums.size() - 1, k = j;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] < nums[i] + nums[j]) {
k = mid;
left = mid + 1;
}
else {
right = mid - 1;
}
}
num += k - j;
}
}
return num;
}
};
排序+双指针:
j和k作双指针,当j向右移动,nums[i] + nums[j]增大,则第三个数一定比原来的下标靠后,则k是一直增大的,所以k只用了n次;
class Solution {
public:
int triangleNumber(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
int ans = 0;
for (int i = 0; i < n; ++i) {
int k = i;
for (int j = i + 1; j < n; ++j) {
while (k + 1 < n && nums[k + 1] < nums[i] + nums[j]) {
++k;
}
ans += max(k - j, 0);
}
}
return ans;
}
};
打败94%的双指针:
class Solution {
public int triangleNumber(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
int res = 0;
for (int i = n - 1; i >= 2; --i) {
int l = 0, r = i - 1;
while (l < r) {
if (nums[l] + nums[r] > nums[i]) {
res += r - l;
--r;
} else {
++l;
}
}
}
return res;
}
}