TopK问题及其延申
912. 排序数组
冒泡
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n=nums.size();
for(int i=0;i<n-1;++i){//冒泡n-1次
for(int j=1;j<n-i;++j){//每次确定最后一位,内层循环少一个
if(nums[j]<nums[j-1]){
swap(nums[j],nums[j-1]);
}
}
}
return nums;
}
};
快排
参考题解
class Solution {
public:
void QuickSort(vector<int>& arr, int start, int end){
if(start >= end) return;
int index=rand()%(end-start+1)+start;
int pivot=arr[index];
swap(arr[start], arr[index]);
int i=start, j=end;
while(i<j){
while(i<j && arr[j]>=pivot)
j--;
while(i<j && arr[i]<=pivot)
i++;
if(i!=j){
swap(arr[i], arr[j]);
}
}
swap(arr[start], arr[i]);
//最后是i==j了,因为先动的j,所以arr[j]可能<pivot,但arr[i]不可能>pivot
QuickSort(arr,start,i-1);
QuickSort(arr,i+1,end);
return;
}
vector<int> sortArray(vector<int>& nums) {
QuickSort(nums, 0, nums.size()-1);
return nums;
}
};
归并
参考题解
class Solution {
public:
void merge(vector<int> &nums, int left, int right, vector<int> &ans){
int mid=(left+right)/2;
int i=left, j=mid+1;
int k=0;
while(i<=mid && j<=right){
if(nums[i]<nums[j]){
ans[k++]=nums[i++];
}
else{
ans[k++]=nums[j++];
}
}
while(i<=mid){
ans[k++]=nums[i++];
}
while(j<=right){
ans[k++]=nums[j++];
}
for(int p=left;p<=right;++p){
nums[p]=ans[p-left];
}
return;
}
void MergeSort(vector<int> &nums, int left, int right, vector<int> &ans){
if(left>=right) return;
int mid=(left+right)/2;
MergeSort(nums, left, mid, ans);
MergeSort(nums, mid+1, right, ans);
merge(nums, left, right, ans);//合并左右两半已排序数组
//return;
}
vector<int> sortArray(vector<int>& nums) {
vector<int> ans(nums.size());
MergeSort(nums, 0, nums.size()-1, ans);
return nums;
}
};
计数排序
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n=nums.size();
int minnum=nums[0],maxnum=nums[0];
for(int i=1;i<n;++i){
if(nums[i]<minnum) minnum=nums[i];
if(nums[i]>maxnum) maxnum=nums[i];
}
vector<int> v(maxnum-minnum+1,0);//maxnum-minnum+1的空间复杂度
for(int i=0;i<n;++i){
v[nums[i]-minnum]++;//对minnum+v中序号计数
}
int start=0;
for(int i=0;i<v.size();++i){
while(v[i]>0){
nums[start]=i+minnum;
start++;
v[i]--;
}
}
return nums;
}
};
215. Top K
部分快排,沿用上面的快排模板,partition返回本轮确定位置的数的下标,如果等于n-k(第k大下标是从小到大序列的n-k),就返回,<n-k,在右边找,>n-k,左边找
topk 的小错:
int index=rand()%(right-left+1)+left;
注意right-left+1
int left=0, right=n-1;
int index=partition(nums, left, right);
注意left,right先声明了,不然下面更新left,right 可能出问题
class Solution {
public:
int partition(vector<int> &nums, int left, int right){
int index=rand()%(right-left+1)+left;
int pivot=nums[index];
swap(nums[index], nums[left]);
int i=left, j=right;
while(i<j){
while(i<j && nums[j]>=pivot) j--;
while(i<j && nums[i]<=pivot) i++;
if(i!=j){
swap(nums[i], nums[j]);
}
}
swap(nums[left], nums[i]);
return i;
}
int findKthLargest(vector<int>& nums, int k) {
//第k大,下标是n-k,第1大是n-1,类推
int n=nums.size();
k=n-k;
int left=0, right=n-1;
int index=partition(nums, left, right);
while(index!=k){
if(index<k){
left=index+1;
}
else right=index-1;
index=partition(nums, left, right);
}
return nums[index];
}
};
手写大根堆
参考题解
有没有更快的方法
计数排序,但是空间复杂度高
桶排序:大数据或者内存不足的情况使用,O(N)找到最大最小数,差值t,分根号t个桶子,小于最小数+根号t的放在第一个桶子里,以此类推,O(n)+O(n^(1/2)*log( n^(1/2 ))
链表排序
8. 字符串转换整数 (atoi)
自己写的版本,用long,maxvalue是最大,minvalue是最小的绝对值。
class Solution {
public:
int myAtoi(string s) {
int k=0;
int n=s.size();
long ans=0;
long maxvalue=pow(2,31)-1;
long minvalue=pow(2,31);
if(n==0) return 0;
while(k<n){
if(s[k]==' ') k++;
else break;
}
bool neg=0;
if(s[k]=='+') k++;
else if(s[k]=='-'){
neg=1;
k++;
}
while(k<n){
if(!isdigit(s[k])) break;
else{
if(!neg && (ans==maxvalue/10 )&& ((int(s[k]-'0')>=maxvalue%10))){
ans=maxvalue;
return ans;
}
else if(neg &&( ans==minvalue/10) && ((int(s[k]-'0')>=minvalue%10))){
ans=0-minvalue;
return ans;
}
else if(!neg && (ans>maxvalue/10 )){ return maxvalue;}
else if(neg && ( ans>minvalue/10)) return -1*minvalue;
ans=ans*10+(int(s[k]-'0'));
k++;
}
}
if(neg) return -1*ans;
else return ans;
}
};
优化边界处理,这里可以不用long,maxalue设置成MAX_INT/10就可
class Solution {
public:
int myAtoi(string s) {
int k=0;
int n=s.size();
long ans=0;
long maxvalue=pow(2,31)-1;
long minvalue=pow(2,31);
if(n==0) return 0;
while(k<n){
if(s[k]==' ') k++;
else break;
}
bool neg=0;
if(s[k]=='+') k++;
else if(s[k]=='-'){
neg=1;
k++;
}
while(k<n){
if(!isdigit(s[k])) break;
else{
int num=int(s[k]-'0');
if(ans>maxvalue/10){
if(neg) return -minvalue;
else return maxvalue;
}
else if(ans==maxvalue/10){
if(!neg && num>=maxvalue%10) return maxvalue;
else if(neg && num>=minvalue%10) return -minvalue;
}
ans=ans*10+num;
k++;
}
}
if(neg) return -ans;
else return ans;
}
};
查找两个数的中位数(一步步深入,先从空间复杂度O(n+m)到时间负责度O(n+m)到O(log(n+m))
层序遍历
非递归中序遍历 栈->Morriss
336. 回文对
暴力解法(超时)
class Solution {
public:
bool ishuiwen(string str){
int n=str.size();
if(n<=1) return true;
int start=0,end=n-1;
while(start<end){
if(str[start]==str[end]){
start++;
end--;
}
else return false;
}
return true;
}
vector<vector<int>> palindromePairs(vector<string>& words) {
int n=words.size();
vector<vector<int>> v;
for(int i=0;i<n;++i){
for(int j=0;j<n; ++j){
if(j==i) continue;
string str=words[i]+words[j];
if(ishuiwen(str)){
v.push_back({i,j});
}
}
}
return v;
}
};
哈希表解法
看起来就这个比较好写,适合面试手撕,故取这个。
官方题解
其他解法:
字典树
字典树+马拉车
504. 七进制数
除留余数法
class Solution {
public:
string convertToBase7(int num) {
if(num==0) return "0";
bool neg=num>0;
string s="";
num=abs(num);
while(num>0){
s.push_back('0'+num%7);
num/=7;
}
if(!neg) s.push_back('-');
reverse(s.begin(), s.end());
return s;
}
};
1143. 最长公共子序列
O(m*n)
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m=text1.size(), n=text2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1,0));
int ans=0;
for(int i=1;i<=m;++i){
for(int j=1; j<=n; ++j){
if(text1[i-1]==text2[j-1]){
//i 和j是dp的下标,增加一行0和一列0,从1到n
dp[i][j]=dp[i-1][j-1]+1;
ans=max(ans, dp[i][j]);
}
else{
dp[i][j]=max(dp[i-1][j], dp[i][j-1]);
ans=max(ans, dp[i][j]);
}
}
}
return ans;
}
};
300. 最长递增子序列
//O(nlogn)
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> tails(nums.size(),0);
int res=0;
for(auto num:nums){
int i=0, j=res;
while(i<j){
int m=(i+j)/2;
if(num>tails[m]) i=m+1;
else j=m;
}
tails[i]=num;
if(j==res) res++;
}
return res;
}
};
// O(n^2)
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int ans=1;
int n=nums.size();
vector<int> dp(n,1);
for(int i=0; i<n;++i){
for(int j=0; j<i;++j){
if(nums[i]<=nums[j]){
continue;
}
else{
dp[i]=max(dp[i], dp[j]+1);
}
}
}
for(auto k:dp){
ans=max(ans,k);
}
return ans;
}
};
二分法解方程
以算根号2为例
double d=2;
double eps = 0.000001;
double f(double x) {
return x * x;
}
int main() {
double l = 0, r = d;
double mid = (l + r) / 2;
while (abs(f(mid)-d) >= eps) {
mid = (l + r) / 2;
if (f(mid) - d < 0) {
l = mid;
}
else r = mid;
}
cout << setprecision(7) << mid << endl;
return 0;
}
x^3+4*x-10=0在(1,2)的近似解
double d=0;
double eps = 0.000001;
double f(double x) {
//return x * x;
return pow(x, 3) + 4 * x - 10;
}
int main() {
double l = 1, r = 2;
double mid = (l + r) / 2;
while (abs(f(mid)-d) >= eps) {
mid = (l + r) / 2;
if (f(mid) - d < 0) {
l = mid;
}
else r = mid;
}
cout << setprecision(7) << mid << endl;
return 0;
}