1、寻找峰值
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞。
要求:你的解法应该是O(logN)时间复杂度的。
参考思路:
方法一:线性扫描:时间复杂度O(n),空间复杂度O(1)。
方法二:二分查找:O(logN)时间复杂度。
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int right=nums.size()-1, left=0,m;
while(left<right)
{
m=(right+left)/2;
if(nums[m+1]<nums[m])right=m;
else left=m+1;
}
return left;
}
};
2、寻找重复数
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
要求:不能更改原数组(假设数组是只读的)。只能使用额外的 O(1) 的空间。时间复杂度小于 O(n2) 。数组中只有一个重复的数字,但它可能不止重复出现一次。
解答:
鸽子洞原理/抽屉原理:有n只鸽子和m个鸽洞,所有鸽子都住在鸽洞里,如果n>m,那么至少有2只鸽子必须住在同一鸽洞里。
https://leetcode-cn.com/problems/find-the-duplicate-number/solution/287xun-zhao-zhong-fu-shu-by-kirsche/
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow=0,fast=0;
slow=nums[slow];
fast=nums[nums[fast]];
while(slow!=fast)
{
slow=nums[slow];
fast=nums[nums[fast]];
}
int pre1=0,pre2=slow;
while(pre1!=pre2)
{
pre1=nums[pre1];
pre2=nums[pre2];
}
return pre1;
}
};
3、计算右侧小于当前元素的个数
给定一个整数数组nums,按要求返回一个新数组counts。数组counts有该性质:counts[i]的值是nums[i]右侧小于nums[i]的元素的数量。
解答:归并排序 + 索引数组
https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/solution/gui-bing-pai-xu-suo-yin-shu-zu-python-dai-ma-java-/
class Solution {
vector<int>index;
vector<int>helper;
vector<int>count;
public:
void merge(const vector<int> &nums,int lo,int mi,int hi)
{
if(lo==mi)return ;
if(mi==hi)return ;
// 先merge两个小的
merge(nums, lo, (lo + mi) >> 1, mi);
merge(nums, mi, (mi + hi) >> 1, hi);
// 把需要用的index拷贝到helper里面,一会儿直接往index里面写就好了
for (int k = lo; k < hi; k++) helper[k] = index[k];
// 合并两个有序数组,并计算向右移动的位数(即右边有几个比当前元素小)
int p1 = lo, p2 = mi, p = lo;
while (p1 != mi or p2 != hi) {
if (p1 == mi) {
index[p++] = helper[p2++];
} else if (p2 == hi) {
index[p++] = helper[p1++];
count[index[p - 1]] += (p2 - mi); // p2 - mi即右边出了多少个
} else if (nums[helper[p2]] < nums[helper[p1]]) {
index[p++] = helper[p2++];
} else {
index[p++] = helper[p1++];
count[index[p - 1]] += (p2 - mi); // p2 - mi即右边出了多少个
}
}
}
vector<int> countSmaller(vector<int>& nums) {
int len=nums.size();
if(len==0)return {};
if(len==1)return {0};
index.resize(len);
helper.resize(len);
count.resize(len);
for(int i=0;i<len;i++)
{
index[i]=i;
count[i]=0;
}
//merge
merge(nums,0,len/2,len);
return count;
}
};
4、摆动排序 II
给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。
要求:用 O(n) 时间复杂度和 / 或原地 O(1) 额外空间来实现。
解答:快速选择 + 3-way-partition + 虚地址
https://leetcode-cn.com/problems/wiggle-sort-ii/solution/yi-bu-yi-bu-jiang-shi-jian-fu-za-du-cong-onlognjia/
class Solution {
public:
void wiggleSort(vector<int>& nums) {
int n = nums.size();
// Find a median.
auto midptr = nums.begin() + n / 2;
nth_element(nums.begin(), midptr, nums.end());
int mid = *midptr;
// Index-rewiring.
#define A(i) nums[(1+2*(i)) % (n|1)]
// 3-way-partition-to-wiggly in O(n) time with O(1) space.
int i = 0, j = 0, k = n - 1;
while (j <= k) {
if (A(j) > mid)
swap(A(i++), A(j++));
else if (A(j) < mid)
swap(A(j), A(k--));
else
j++;
}
}
};
5、最大数
给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。输出结果可能非常大,所以你需要返回一个字符串而不是整数。
解答:下面是在题解里找到的两个很厉害的答案。
方法一:一套STL走天下,tql
class Solution {
public:
string largestNumber(vector<int>& nums)
{
if (all_of(nums.begin(), nums.end(), [](int x) { return x == 0; })) {
return string("0");
}
vector<string> strNums(nums.size());
std::transform(nums.begin(), nums.end(), strNums.begin(), [](int x) {
return std::to_string(x);
});
std::sort(strNums.begin(), strNums.end(), [](const string& x, const string& y) {
/* x为后面元素,y为前面元素,return true则将x移动到前面 */
return x + y > y + x;
});
return std::accumulate(strNums.begin(), strNums.end(), string());
}
};
方法二:实现一个自定义排序。
将输入的数组按照某个顺序排序,然后按顺序组合就是最大数。
这个顺序的目的是实现组合后较大的数字在前面。
所以排序的比较算法应该是对组合后的数字进行比较。
通过计算进行比较的两个数字的位数,交叉相乘再相加(a * b的位数 + b),实现将两个数字组合到一起。
链接:https://leetcode-cn.com/problems/largest-number/solution/179-by-ikaruga/
class Solution {
public:
string largestNumber(vector<int>& nums)
{
auto f_sort = [](const int &a, const int &b)
{
long long n_a = 10;
while (a / n_a) n_a *= 10;
long long n_b = 10;
while (b / n_b) n_b *= 10;
long long r_a = (long long)a * n_b + (long long)b;
long long r_b = (long long)b * n_a + (long long)a;
return r_a < r_b;
};
sort(nums.rbegin(), nums.rend(), f_sort);
string ans;
for (auto n : nums)
{
ans = (ans == "0") ? to_string(n) : ans + to_string(n);
}
return ans;
}
};