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;
}
};