• 力扣刷题--数组1


    一:移动零(力扣283)

    1. void moveZeroes(vector<int>& nums) {
    2. //申请一个辅助数组,存放非零元素,然后再赋值给原数组
    3. vector<int> aux;
    4. for(int i=0;isize();i++){
    5. if(nums[i])
    6. aux.push_back(nums[i]);//借用向量的push_back函数
    7. }
    8. for(int i=0;isize();i++){
    9. nums[i]=aux[i];
    10. }
    11. //补0
    12. for(int i=aux.size();isize();i++){
    13. nums[i]=0;
    14. }
    15. }

    很简单的一个思路:

           申请额外数组存储原数组非零元素(利用push_back),然后赋值回给原数组,最后在末位编变成0

    法二:

    1. void moveZeroes(vector<int>& nums) {
    2. /*
    3. 原地实现该功能,不申请额外空间:
    4. 定义一个索引k,指向数组第一个元素,i用于遍历数组,如果是非零元素把值赋给k位置。
    5. k更新到下一个位置,直至遍历结束,从k开始往后补0
    6. */
    7. int k=0;//nums中[0,k)存储非零元素
    8. //for循环,不断把非零元素依次赋值给k
    9. for(int i=0;isize();i++)
    10. if(nums[i]){//nums[i]不为0
    11. nums[k++]=nums[i];//别忘了移动k索引
    12. }
    13. //补零
    14. for(int i=k;isize();i++)
    15. nums[i]=0;
    16. }

    法三:零与非零的交换

    1. void moveZeroes(vector<int>& nums) {
    2. int k=0;//nums中[0,k)存储非零元素
    3. for(int i=0;isize();i++)
    4. if(nums[i]){
    5. swap(nums[i],nums[k]);
    6. k++;
    7. }
    8. }

    与法二相比,由于直接交换,少了重新赋值为0操作

    优化细节:

    避免自己和自己交换,可以考虑i与k的大小关系

    if(i!=k)  swap(nums[k++],nums[i]);

    else k++;

    二:挑选颜色

    1. void sortColors(vector<int>& nums) {
    2. /*
    3. 因为元素只有0,1,2三种可能,所以采用计数排序思想:
    4. 分别统计出:0的个数,1的个数以及2的个数,赋值即可
    5. */
    6. int count[3]={0};
    7. for(int i=0;isize();i++){
    8. assert(nums[i]>=0&&nums[i]<=2);
    9. count[nums[i]]++;//数值直接对应频次
    10. }
    11. //定义一个不断累计的索引
    12. int index=0;
    13. for(int i=0;i0];i++)
    14. nums[index++]=0;
    15. for(int i=0;i1];i++)
    16. nums[index++]=1;
    17. for(int i=0;i2];i++)
    18. nums[index++]=2;
    19. }

    几个代码小细节:

    • 因为只有0,1,2且想累计出现个数,直接以元素值计算频次
    • 由于从头一次按照个数赋值0,1,2;所以直接建立一个不断累计的index

     其实可以把三路快排的思想移到这

    这是最后想达到的效果:

     其实关键在于对遍历索引i的元素处理:

     分以下三种情况:

     如果元素为1,i右移

     如果元素是2,和two前一个元素交换,i不动,two--

     如果元素是1,和zero后元素交换,zero++,i++

    代码实现

    1. #include
    2. #include
    3. using namespace std;
    4. class soluction{
    5. public:
    6. void sortColors(vector<int>& nums){
    7. /*
    8. 功能实现:
    9. [0,zero]全是0----也就是zero初始化为-1
    10. [two,n-1]全是1---也就是two初始化为n(假设nums长度为n)
    11. 索引i遍历数组,遇到1右移,控制(zero,two)范围全是1
    12. */
    13. int zero=-1;
    14. int two=nums.size();
    15. int i=0;//从头遍历数组
    16. while( i//遍历结束条件
    17. if(nums[i]==1) i++;
    18. else if(nums[i]==2){
    19. two--;
    20. swap(nums[two],nums[i]);
    21. }
    22. else{//nums[i]==0
    23. zero++;
    24. swap(nums[i],nums[zero]);
    25. i++;
    26. }
    27. }
    28. }
    29. };
    30. int main(){
    31. int arr[]={1,0,2,0,2,1,1,2,0};
    32. vector<int> vec(arr,arr+sizeof(arr)/sizeof(int));
    33. soluction().sortColors(vec);
    34. for(vector<int>::iterator it=vec.begin();it!=vec.end();it++)
    35. cout<<(*it)<<" ";
    36. }

    快速排序两种实现

    1. #include
    2. #include
    3. using namespace std;
    4. int partition(vector<int>& a,int L,int R){
    5. /*
    6. 索引i记录小于基准元素的最后一个位置,初始化为基准元素位置
    7. 索引j用于遍历
    8. j遇到的元素≥基准元素---往后遍历
    9. j遇到的元素<基准元素---交换i后位置和当前位置,i++
    10. */
    11. int e=a[L];//以最左边元素为基准元素
    12. int i=L;
    13. int j=L+1;
    14. for(;j<=R;j++){
    15. if(a[j]
    16. swap(a[++i],a[j]);
    17. }
    18. }
    19. swap(a[L],a[i]);
    20. return i;
    21. }
    22. void quickSortHelper(vector<int>& a,int L,int R){
    23. if(L>=R) return;//递归结束
    24. int p=partition(a,L,R);
    25. quickSortHelper(a,L,p-1);
    26. quickSortHelper(a,p+1,R);
    27. }
    28. void quickSort(vector<int>& a){//一定要加&
    29. quickSortHelper(a,0,a.size()-1);
    30. }
    31. int main(){
    32. vector<int> arr={1,22,3,55,66,7,2,11,1,3,4};
    33. quickSort(arr);
    34. vector<int>::iterator it;
    35. for(it=arr.begin();it!=arr.end();it++){
    36. cout<<(*it)<<" ";
    37. }
    38. return 0;
    39. }

    注意要在vector加上*,否则原向量不改变

    1. /*
    2. 双指针法:
    3. i不断右移,使得其之前的元素均≤基准元素
    4. j不断左移,使得其之后的元素均≥基准元素
    5. 如果i,j均停止,交换两者所指元素,然后i右移,j左移
    6. 最后----把j位置,即小于基准元素最后一个元素和基准元素交换
    7. */
    8. int e=a[L];
    9. int i=L+1,j=R;//i,j指向除基准元素的两头
    10. while(1){
    11. while(i<=j&&a[i]<=e) i++;
    12. while(i<=j&&a[j]>=e) j--;
    13. if(i>j) break;
    14. swap(a[i++],a[j--]);
    15. }
    16. swap(a[L],a[j]);
    17. return j;
    18. }

     三:寻找第k个大的元素

     这里要用到一个快速排序分区的性质:

    每次快排后,都可以确定该元素在顺序中的正确位置。

    也就是说:排序后,倒数第一个最大,倒数第二个第二大。。。。

    只要快排的索引落在了该位置,该位置就可以确定第几大或第几小

    1. int partition(vector<int>& nums,int l,int r){
    2. int e=nums[l];
    3. int i=l;
    4. int j=l+1;
    5. for(;j<=r;j++){
    6. if(nums[j]
    7. swap(nums[j],nums[++i]);
    8. }
    9. swap(nums[l],nums[i]);
    10. return i;
    11. }
    12. int findKthLargest(vector<int>& nums, int k) {
    13. int target=nums.size()-k;
    14. int l=0;
    15. int r=nums.size()-1;
    16. while(1){//条件:L<=R,但是该题一定有解,无需判断
    17. int p=partition(nums,l,r);
    18. if(p==target) return nums[p];
    19. else if(p>target) r=p-1;
    20. else l=p+1;
    21. }
    22. }
  • 相关阅读:
    CentOS 8里的这个功能,天翼云SFS弹性文件校准了
    智慧工地管理系统(Smart site management system)源码
    Hadoop架构、Hive相关知识点及Hive执行流程
    Go-Excelize API源码阅读(三十六)——SetSheetRow、InsertPageBreak
    悬赏任务兼职众人帮蚂蚁帮扶任务平台
    集成学习-Boosting
    没有二十年功力,写不出Thread.sleep(0)这一行“看似无用”的代码!
    vue前端开发ios系统:https发http请求 网络通讯之间的安全问题
    Spark写入支持更新【源码二次开发】
    国内BLDC电机控制方案目前存在什么痛点?
  • 原文地址:https://blog.csdn.net/weixin_47173597/article/details/126771057