01-算法-认识复杂度和简单排序算法

1. 认识复杂度和简单排序算法。

第1节、时间复杂度

先从选择排序看起

选择排序:从第1位到第N位。每一位分别与之后的所有数比较。比较小的树放在第i位。

在这里插入图片描述

计算时间复杂度:

​ 每一个数分别看了后面的数:N次、N-1次、N-2次···1次。

​ 每个数分别比较了后面的数:N次、N-1次、N-2次···1次。

​ 每个数都交换了一次:1次。

所以可以得出时间复杂度:

​ 每个数看了: N+N-1+N-2+···+1。

​ 每一个数比较了: N+N-1+N-2+···+1。

​ 总共交换了N次。

全部相加可以得到: (N+1)*N + N 。

它是一个: 最高次项为二次的方程 aN^2+bN+c。

得到时间复复杂度为 O(N^2) 读作:big o N^2。

第2节、额外空间复杂度(选择排序)

这里我们也可以从选择排序看起

下面我们给出选择排序的代码:

namespace LeetCode_Learn
{
    public class Part01_SelectionSort
    {
        public static int[] Sort(int[] arr)
        {
            if (arr == null)
                throw new ArgumentNullException("arr不可为空!");
            if (arr.Length < 2)
                return arr;

            for (int i = 0; i < arr.Length; i++)
            {
                int minIndex = i;
                for (int j = i + 1; j < arr.Length; j++)
                {
                    minIndex = arr[j] < arr[minIndex] ? j : minIndex;
                }
                Swap(arr, i, minIndex);
            }

            return arr;
        }

        private static void Swap(int[] arr, int index1, int index2)
        {
            int temp = arr[index1];
            arr[index1] = arr[index2];
            arr[index2] = temp;
        }
    }
}

在遍历每个数字的时候,我们会声明一个temp作为最小的最小的index。每次去每次循环完之后会释放掉这个temp,所以这里我们只用到了开辟了一个变量。也就是额外空间复杂度为O(1) 。

第3节、冒泡排序

冒泡排序:遍历每个数,其左边边的数做以下操作: 如果右边的数大于左边的数则交换。

在这里插入图片描述

下面给出代码:

namespace LeetCode_Learn
{
    public class Part02_BubbleSort
    {
        public static int[] Sort(int[] arr)
        {
            if (arr == null)
                throw new ArgumentNullException("arr不可为空!");
            if (arr.Length < 2)
                return arr;

            for (int i = arr.Length - 1; i >= 0; i--)
            {
                for (int j = 0; j < i; j++)
                {
                    if (arr[j] > arr[j + 1])
                    {
                        Swap(arr, j, j + 1);
                    }
                }
            }

            return arr;
        }

        private static void Swap(int[] arr, int index1, int index2)
        {
            arr[index1] = arr[index1] ^ arr[index2];
            arr[index2] = arr[index1] ^ arr[index2];
            arr[index1] = arr[index1] ^ arr[index2];
        }
    }
}

这里用到异或运算进行。进行交换操作。

在这里插入图片描述

第4节、异或运算

下面给出异或运算的一些规律:

  1. 0^N = N。

  2. N^N = 0。

  3. 符合交换律和结合律。

  4. 异或运算与顺序无关,可以调换顺序。

  5. 注意事项:如果要进行用异或运算进行交换操作,请注意a和b指向的内存空间不能为同一个。因为N^N=0。

下面给出一道异或运算的练习题:

​ 给出一个整形数组 int[] arr

​ 第1问:这个数组中仅有一种数出现奇数次,其他数都是偶数次。求这个基数是多少?

​ 第2问:这个数组中仅有二种数出现奇数次。其他数都是都是偶数次。求这两个奇数分别是多少?

​ 第1题,题解:

​ 定义eor = 0,用eor 异或每一个数得到的数一定是出现奇数次的数。因为出现偶数次的数异或为0。

namespace LeetCode_Learn
{
    public class Part03_GetOneOddNumber
    {
        public static int Get(int[] arr)
        {
            if (arr == null)
                throw new ArgumentNullException("arr不可为空!");
            if (arr.Length < 2)
                return arr[0];

            int eor = 0;
            for (int i = 0; i < arr.Length; i++)
            {
                eor ^= arr[i];
            }

            return eor;
        }
    }
}

​ 第2题,题解:

​ 同上题用eor异或每一个数。得到的eor为 a异或b。 a和b是那两个出现奇数次的数。然后我们在定义一个变量_eor = 0。因为a和b不为同一个数,所以 eor不等于0。所以我们一定可以在eor中找到一位为1。这里我们用一个算法来找到最右侧的1:

​ 算法为 rightOne = eor & (~eor+1) 。

​ a和b在rightOne这一位,一定有一位是1,有一位是0。这里我们将数组分为两种类型。种是对应位为1,一种是对应位为0。a和b肯定只占一种类型。然后我们遍历对应位为1的数。用_eor异或这些数。我们一定可以得到a或者b。然后我们再用得到的这个数,来异或eor。这样我们就得到了这两个数。

namespace LeetCode_Learn
{
    public class Part04_GetTwoOddNumber
    {
        public static int[] Get(int[] arr)
        {
            if (arr == null)
                throw new ArgumentNullException("arr不可为空!");
            if (arr.Length < 2)
                return arr;

            int eor = 0;

            for (int i = 0; i < arr.Length; i++)
            {
                eor ^= arr[i];
            }

            int _eor = 0;
            int rightOne = eor & (~eor + 1);

            for (int i = 0; i < arr.Length; i++)
            {
                if ((arr[i] & rightOne) == 0)
                {
                    _eor ^= arr[i];
                }
            }
            int a = eor ^ _eor;
            int b = eor ^ a;
            return new int[] { a, b };
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值