【leetcode刷题1】复杂度 简单排序算法

本文详细介绍了各种排序算法,如选择排序和冒泡排序,分析了它们的时间复杂度和空间复杂度。此外,还探讨了利用异或进行无额外空间交换数值的方法,以及如何在数组中寻找出现奇数次的数字。同时,提到了插入排序和二分法的应用,包括在有序数组中查找和定位元素。
摘要由CSDN通过智能技术生成

【leetcode刷题1】复杂度 简单排序算法

时间复杂度

常数操作

操作时间和数据量没关系

int a =arr[i]是常数操作,int b=list.get(i)不是常数操作,加减乘除位运算是常数操作。

时间复杂度是按最差情况估计

以选择排序为例

遍历第一个位置到最后一个位置,找到最小的数放第一个位置;然后遍历第二个位置到最后一个位置,找到最小的数放在第二个位置…

时间复杂度分析:

分析时间复杂度就是看包含了多少常数操作。在选择排序中,一共包含看一眼这个数,跟当前最小值比较和交换三种常数操作。

第一次遍历,看了n眼,比较了n次,交换了一次;第二次遍历,看了n-1眼,比较了了n-1次,交换了一次…

最终看了:n+n-1+n-2…+1次
比较了:n+n-1+n-2…+1次
交换了n次

求和计算常数操作的次数应该是: a x 2 + b x + c ax^2+bx+c ax2+bx+c的形式,取最高次项并去掉系数得到时间复杂度为 O ( n 2 ) O(n^2) O(n2)

额外空间复杂度

如果只需要有限几个变量就可以完成,那额外空间复杂度就是 O ( 1 ) O(1) O(1)

如果需要额外数组,还得跟原数组等规模,那额外空间复杂度就是 O ( n ) O(n) O(n)

选择排序

void simpleSort(vector<int>& nums)
{
    int size=nums.size();
    if (size==0 ||size==1)
        return ;
    for(int i=0;i<size;i++)
    {
        int minadd=i;
        int min=nums[i];
        for(int j=i;j<size;j++)
        {
            if(nums[j]<nums[minadd])
            {
                minadd=j;
            }          
        }
        min=nums[minadd];
        nums[minadd]=nums[i];
        nums[i]=min;
    }
}

冒泡排序

基本思想:

  • 基本思想: 冒泡排序,类似于水中冒泡,较大的数沉下去,较小的数慢慢冒起来,假设从小到大,即为较大的数慢慢往后排,较小的数慢慢往前排。
  • 直观表达,每一趟遍历,将一个最大的数移到序列末尾。

算法描述:

比较相邻的元素,如果前一个比后一个大,交换之。

第一趟排序第1个和第2个一对,比较与交换,随后第2个和第3个一对比较交换,这样直到倒数第2个和最后1个,将最大的数移动到最后一位。

第二趟将第二大的数移动至倒数第二位

时间复杂度:与选择排序类似。

void bumbleSort(vector<int>& nums)
{
    int size=nums.size();
    if (size==0 ||size==1)
    return ;
    for(int i=0;i<size;i++)
    {
        for(int j=i;j<size-1;j++)
        {
            if(nums[j]>nums[j+1])
            {
                int t=nums[j+1];
                nums[j+1]=nums[j];
                nums[j]=t;
            }
        }
    }
}

用异或实现两数交换

异或运算满足交换律和结合律 跟顺序没有关系

异或可以看作是无进位相加

0^任何数=任何数本身

//a和b需要是两块独立的内存
int a=12;
int b=17;
a=a^b;//a=12^17 b=17
b=a^b;//a=12^17 b=12^17^17=12^0=12
a=a^b;//a=12^17^12=17 b=12

例题

在一个int数组中

1)有一个数字出现了奇数次,其他的数字都出现了偶数次,怎么找到这个数字

2)有两个数字出现了奇数次,其他的数字都出现了偶数次,怎么找到这两个数字

要求:时间复杂度:O(n),空间复杂度O(1)

1)把所有数全异或起来

2)把所有数全异或起来得到ab,其中必有一位不为零,是a和b不一样的位,根据这一位=1或=0将数组中的数分为两类(一定是一类里面包含a另一类里面包含b),对其中的一类数进行全部异或,得到a或者b,再跟ab异或,得到,另一个。

位运算

提取二进制数最右边的1

int rightone=a&(~a+1)

插入排序

插入排序操作类似于摸牌并将其从大到小排列。每次摸到一张牌后,根据其点数插入到确切位置。

例如我们有一组数字:{5,2,4,6,1,3},我们要将这组数字从小到大进行排列。 我们从第二个数字开始,将其认为是新增加的数字,这样第二个数字只需与其左边的第一个数字比较后排好序;在第三个数字,认为前两个已经排好序的数字为手里整理好的牌,那么只需将第三个数字与前两个数字比较即可;以此类推,直到最后一个数字与前面的所有数字比较结束,插入排序完成。

① 从第一个元素开始,该元素可以认为已经被排序
② 取出下一个元素,在已经排序的元素序列中从后向前扫描
③如果该元素(已排序)大于新元素,将该元素移到下一位置
④ 重复步骤③,直到找到已排序的元素小于或者等于新元素的位置
⑤将新元素插入到该位置后
⑥ 重复步骤②~⑤

插入排序的算法流程跟原来数组的情况有关,时间复杂度按最差情况估计为 O ( n 2 ) O(n^2) O(n2)

//从小到大插入排序
void insertionSort(vector<int>& nums)
{
    int size=nums.size();
    if (size==0 ||size==1)
    return ;
    for(int i=1;i<size;i++)
    {
        for(int j=i-1;j>0 &&nums[j]>nums[j+1];j--)
        {
            int t=nums[j+1];
            nums[j+1]=nums[j];
            nums[j]=t;
        }
    }
}

二分法

1)在一个有序数组中找一个数是不是存在

2)遍历查找时间复杂度O(n),二分法时间复杂度 O ( l o g 2 N ) O(log_2N) O(log2N):一个数一次砍掉一半,几次能砍到1(8->4->2->1)

在一个有序数组中找到大于等于某个数最左侧的位置,只找一个数的话找到了就可以停止,找最左侧位置的话,就一定得二分到结束。

3)一个无序数组中,相邻数一定不相等,求一个局部最小值

首先判断首位是否是局部最小,如果不是那范围内一定存在一个局部最小值,取中点,判断是不是局部最小值,如果不是,取小于M的一侧,在这一侧必存在一个局部最小值,重复上述过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值