1,复杂度和简单排序算法【p2-p3】

news2024/11/18 8:52:20

复杂度和简单排序算法

  • 1,时间复杂度
    • 1.1选择排序
    • 1.2冒泡排序
    • 1.3异或运算
      • 1.3.1性质:
      • 1.3.2案例
        • 例1
        • 例2
    • 1.4插入排序
    • 1.5二分法
      • 1.5.1在一个有序数组中,找某个数是否存在
      • 1.5.2在一个有序数组中,找>=某个数最左侧的位置
      • 1.5.3局部最小值问题
    • 1.6对数器的概念和使用
    • 1.7递归方法和master公式
      • 1.7.1递归方法
      • 1.7.2master公式

1,时间复杂度

请添加图片描述
常数时间操作:加减乘除等少量运算
时间复杂度:在常数操作数量级的表达式中,不要低阶项,只要高阶项,而且忽略系数
大O算法时间复杂度
100N2+90万N:他的时间复杂度为O(N2)
时间复杂度按最差情况估计

1.1选择排序

时间复杂度O(N ^ 2),额外空间复杂度O(1)

#include<iostream> 
#include<algorithm>
using namespace std;
void selectSort(int arr[], int n) 
{
	for (int i = 0; i < n; i++) 
	{
		//寻找[i,n)区间里的最小值 
		int minIndex = i;
		for (int j = i + 1; j < n; j++) 
		{
			if (arr[j] < arr[minIndex])
			{
				minIndex = j;//更新索引		 
			}
		}
		//找到最小位置的索引,然后交换最小位置的数和当前的位置的数
		swap(arr[i], arr[minIndex]);
	}
}
int main() {
	int a[10] = { 10,15,20,1,2,3,6,45,21,22 };
	selectSort(a, 10);
	for (int i = 0; i < 10; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
	return 0;
}

1.2冒泡排序

时间复杂度O(N ^ 2),额外空间复杂度O(1)

#include <iostream>
using namespace std;
int main()
{
	int arr[10] = { 10,50,40,60,80,20,30,70,0,90 };
	int length = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < length - 1; i++)
	{
		for (int j = 0; j < length - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				swap(arr[j], arr[j + 1]);
			}
		}
	}
	for (int i = 0; i < length; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

1.3异或运算

相同为0,不同为1
请添加图片描述

1.3.1性质:

0 ^ N == N
N ^ N == 0
异或运算满足交换律和结合律
a ^ b=b ^ a
a ^ b ^ c=a ^ (b ^ c)
一堆数和一个值异或时和顺序无关,无论顺序如何结果是一样的

a=甲,b=乙
a=a ^ b; //a = 甲 ^ 乙 // b = 乙
b=a ^ b; //a = 甲 ^ 乙 // b = 甲 ^ 乙 ^ 乙 = 甲
a=a ^ b; //a = 甲 ^ 乙 ^ 甲 = 乙 // b = 甲

交换时可以不用额外申请一个空间
注意:使用的前提是两个对象在内存里是俩块独立的区域
例:下列代码中的j和j+1位置不可以在同一个位置,否则会清0这块内存

#include <iostream>
using namespace std;
int main()
{
	int arr[10] = { 10,50,40,60,80,20,30,70,0,90 };
	int length = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < length - 1; i++)
	{
		for (int j = 0; j < length - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				arr[j] = arr[j] ^ arr[j + 1];
				arr[j + 1] = arr[j] ^ arr[j + 1];
				arr[j] = arr[j] ^ arr[j + 1];
			}
		}
	}
	for (int i = 0; i < length; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

1.3.2案例

例1

已知一种数出现奇数次,其他数出现偶数次,怎么找到出现奇数次的数
限定:时间复杂度O(N)、空间复杂度O(1)
答:用一个变量int eor=0
把eor从第一个数异或到最后一个数,最后eor为这个出现奇数次的数
请添加图片描述

例2

已知两种数出现奇数次,其他数出现偶数次,怎么找到出现这两种数
限定:时间复杂度O(N)、空间复杂度O(1)
空间复杂度O(1)代表不会开辟新空间
答:用一个变量int eor=0,设出现奇数次的数为a和b,其他都为出现偶数次的数
用eor从第一个数异或到最后一个数,最后eor=a ^ b
因为是两种数,所以a!=b,所以eor!=0
再准备一个变量int eor‘=0,用eor’从第一个数异或到eor异或中偶数位上进行异或后不为0的整数(不存在异或状态),所以eor‘=a or b
所以a or b的另一个数=eor ^ eor’

#include <iostream>
#include <vector>

std::vector<int> findOddOccurrences(std::vector<int>& nums) {
    int eor = 0; // 用于存储最终结果 a ^ b

    for (int num : nums) {
        eor ^= num; // 求异或
    }

    // 找到 a 和 b 不相同的位
    int rightmostBit = eor & (-eor);

    int eor1 = 0;
    for (int num : nums) {
        if ((num & rightmostBit) != 0) {
            eor1 ^= num;
        }
    }

    int eor2 = eor ^ eor1;

    return { eor1, eor2 };
}

int main() {
    std::vector<int> nums = { 2, 2, 4, 4, 5, 5, 3, 6, 6, 7 };
    std::vector<int> result = findOddOccurrences(nums);

    std::cout << "Numbers that appear odd number of times: " << result[0] << " and " << result[1] << std::endl;

    return 0;
}

方法二
用一个变量int eor=0,设出现奇数次的数为a和b,其他都为出现偶数次的数
用eor从第一个数异或到最后一个数,最后eor=a ^ b
因为是两种数,所以a!=b,所以eor!=0
eor&(~eor+1)提取出最右边的1
请添加图片描述

1.4插入排序

7,6,5,4,3,2,1
最多排序次数1+2+3+4+5+6
时间复杂度O(N ^ 2),额外空间复杂度O(1)
1,2,3,4,5,6,7
最少排序次数0
时间复杂度按最差情况估计

arr[] = {3,2,5,4,2,3,3}
0到0号位变为有序
3和3比较,3
0到1号位变为有序
2和3比较,3大,2,3
2和自己比较,停
0到2号位变为有序
5和3比较,5大,2,3,5
0到3号位变为有序
4和5比较,5大,2,3,4,5
4和3比较,4大,停
0到4号位变为有序
2和5比较,5大,2,3,4,2,5
2和4比较,4大,2,3,2,4,5
2和3比较,3大,2,2,3,4,5
2和2比较,相同,停
0到5号位变为有序
3和5比较,5大,2,2,3,4,3,5
3和4比较,4大,2,2,3,3,4,5
3和3比较,相同,停
…………

#include <iostream>
void test01()
{
    int arr[] = { 3,2,5,4,2,3,3 };
    int length = sizeof(arr) / sizeof(arr[0]);
    for (int i = 0; i < length ; i++)
    {
        for (int j = i; j >0; j--)
        {
            if (arr[j] < arr[j-1])
            {
                arr[j] = arr[j] ^ arr[j-1];
                arr[j-1] = arr[j] ^ arr[j-1];
                arr[j] = arr[j] ^ arr[j-1];
            }
            else
            {
                break;
            }
        }
    }
    for (int q = 0; q < length; q++)
    {
        std::cout << arr[q] << " ";
    }
    std::cout << std::endl;
}

int main() 
{
    test01();
    return 0;
}

1.5二分法

时间复杂度O(log2N)(logN就是log2N),log3N

1.5.1在一个有序数组中,找某个数是否存在

从小到大的有序数组,找num
如果采用遍历,时间复杂度为O(N)
二分法为O(log2N)(logN就是log2N
先找到中点x,如果x>num则找左侧继续二分,如果x<num则找右侧继续二分

1.5.2在一个有序数组中,找>=某个数最左侧的位置

1.5.3局部最小值问题

arr中无序,相邻两数一定不相等
在0位置a,1位置b,a<b则a为局部最小
在end位置a,end-1位置b,b<a则b为局部最小
在N位置,N+1和N-1位置都比N大,则N为局部最小
找到一个局部最小数,时间复杂度好于O(N)与否?

先看0和1,N-2和N-1位置看大小,0或N-1小就直接输出了
0比1大,N-1比N-2大,那么0到N-1必定存在至少一个拐点
取中点M,看M-1和M-2位置比大小,如果最小直接输出
如果不是最小,那么比M小的一侧必有拐点,
一边小则在小的一边继续二分
两边小则随机取一边继续二分

体现了两种优化,数据状况,问题标准

1.6对数器的概念和使用

有一个想要测的方法a
实现复杂度不好但是容易实现的方法b
实现一个随机样本产生器
把方法a和方法b跑相同的随机样本,看看得到的结果是否一样
如果有一个随机样本使得对比结果不一致,打印样本进行人工干预,改对方法a或者方法b
当样本数量很多时比对测试依然正确,可以确定方法a已经正确

c++随机样本产生器
int randroom=rand()%999+2;
生成0+2到998+2的数值

// 对数器.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>

using namespace std;

//有一个你想要测试的算法,这里以归并排序为例
class Solution {
public:
    static int reversePairs(vector<int>& nums) {
        auto L = 0;
        auto R = nums.size() - 1;
        auto res = 0;
        mergesort(nums, L, R);
        return res;
    }

    //归并排序,从大到小排列(逆序)
    static void mergesort(vector<int>& nums, int L, int R)
    {
        //递归终止条件
        if (L >= R)
        {
            return;
        }
        //序列中心位置计算
        auto mid = (L + ((R - L) >> 1));
        //auto mid = (R + L) / 2;
        //左右序列分别排序
        mergesort(nums, L, mid);
        mergesort(nums, mid + 1, R);

        //归并两个排好序的序列
        merge(nums, L, mid, R);
    }

    static void merge(vector<int>& nums, int L, int mid, int R)
    {
        //临时向量存储归并的结果
        vector<int> tmp(R - L + 1);
        auto pos = 0;
        auto Lp = L;
        auto Rp = mid + 1;
        while ((Lp <= mid) && (Rp <= R))
        {
            tmp[pos++] = (nums[Lp] < nums[Rp]) ? nums[Lp++] : nums[Rp++];
        }
        while (Lp <= mid)
        {
            tmp[pos++] = nums[Lp++];
        }
        while (Rp <= R)
        {
            tmp[pos++] = nums[Rp++];
        }

    	//将排序好部分拷贝至nums数组
        copy(nums, tmp, L, R);
        //nums = tmp;
    }

	//部分数组拷贝函数
    static void copy(vector<int>& nums, vector<int>& tmp, int L, int R)
    {
        auto pos = 0;
        for (auto i = L; i <= R; i++)
        {
            nums[i] = tmp[pos++];
        }
    }
};


//准备一个随机数组(样本)生成器
//函数名:generateRandomVector
//函数功能描述:随机数组(样本)生成器
//函数参数: size    生成数组最大尺寸
//         value   数组每个元素的最大值
//返回值:  vector<int> 生成的数组
//for test
vector<int> generateRandomVector(int size, int value)
{
    //time 函数返回从 1970 年 1 月 1 日午夜开始到现在逝去的秒数,因此每次运行程序时,它都将提供不同的种子值。
    srand((int)time(NULL));//为随机数生成器产生随机种子
    //分配随机大小的数组,产生随机数的范围公式number = (rand()%(maxValue - minValue +1)) + minValue;
    vector<int> result(rand() % (size + 1));
    for (auto i = 0; i < result.size(); i++)
    {
        result[i] = rand() % (value + 1);
    }

    return result;

}

//大样本测试
//函数名:main
//函数功能描述:大样本测试
//函数参数: size    生成数组最大尺寸
//         value   数组每个元素的最大值
//返回值:  vector<int> 生成的数组
//for test
int main()
{
    auto test_time = 50000;//测试次数,设置比较大,排除特殊情况
    auto size = 10;//生成数组最大尺寸
    auto value = 30;//生成数组每个元素的最大值
    auto if_accept = true;//方法是否正确标志位
	for(auto i = 0; i < test_time; i++)
	{
        //拷贝初始化,生成新的数组向量
        vector<int> nums(generateRandomVector(size, value));
        //生成两个临时数组拷贝
        vector<int> nums1(nums);
        vector<int> nums2(nums);

		//绝对正确方法
        sort(nums1.begin(), nums1.end());
		//自己写的方法,想要测试的算法
        Solution::reversePairs(nums2);

		//判断两个向量是否相同,vector类已经重载了比较运算符,不用自己实现,不相同说明算法不正确
		if(nums1 != nums2)
		{
            if_accept = false;
			//输出结果不相等的原始向量
			for(auto c: nums)
			{
                cout << c << " ";
			}
			break;
		}
		
	}
	

	//输出结果
    cout << (if_accept ? "nice!\n" : "false!\n");
    
}

1.7递归方法和master公式

1.7.1递归方法

目的:
递归行为和递归行为时间复杂度的估算
怎么用递归方法找一个数组中的最大值,系统是怎么操作的

递归基(base case):确定递归应该结束的条件,通常是问题规模达到最小的情况。
递归步骤(recursive step):将原问题分解为更小的子问题,并通过递归调用来解决这些子问题。
在使用递归时需要注意处理边界条件,避免无限递归和过深的递归栈

中点mid
mid=(L+R)/2,但是万一LR太大,可能会导致溢出,使结果变为负数出错
mid=L+(R-L)/2
请添加图片描述
p(0,5)->p(0,2)->p(0,1)->p(0,0)-返回结果>p(0,1)->p(1,1)-返回结果>p(0,1)-返回结果,取消p(0,1)压栈>p(0,2)->p(2,2)-返回结果>p(0,2)-返回结果,取消p(0,2)压栈>p(0,5)->p(3,5)->p(3,4)->p(3,3)-返回结果>p(3,4)->p(4,4)-返回结果>p(3,4)-返回结果,取消p(3,4)压栈>p(3,5)->p(5,5)-返回结果>p(3,5)-返回结果,取消p(3,5)压栈>p(0,5)

1.7.2master公式

master公式
T(N)=a* T(N/b)+O(N^d)
log(b,a)>d -> 复杂度为 O(N^log(b,a))
log(b,a)=d -> 复杂度为 O(N^d *logN)
log(b,a)< d -> 复杂度为 O(N^d)

T(N)母问题的数据量是T(N)级别的有N个数据
T(N/b)子问题的规模
a为子问题调用次数
O(N^d)除去调用之外剩下的过程的时间复杂度

使用master公式 需要看子问题规模是不是等量的,等量才可以使用

三个值一旦确定即可找出时间复杂度
logba<d 的时间复杂度O(Nd)
logba>d 的时间复杂度O(N^logb a )
logba==d 的时间复杂度O(Nd * logN)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/813915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux系统编程重点复习--守护进程和线程

复习目标 说出守护进程的特点独立完成守护进程的创建独立实现多个线程的创建独立实现线程的退出和资源回收理解线程同步的思想 1 守护进程 1.1 守护进程介绍 Daemon(精灵)进程&#xff0c;是Linux中的后台服务进程&#xff0c;通常独立于控制终端并且周期性地执行某种任务或…

通向架构师的道路之Apache整合Tomcat

一、先从J2EE工程的通用架构说起 这是一个通用的Web即B/S工程的架构&#xff0c;它由&#xff1a; Web Server App Server DB Server 三大部分组成&#xff0c;其中&#xff1a; Web Server 置于企业防火墙外&#xff0c;这个防火墙&#xff0c;大家可以认为是…

hugging face下载数据集

开始直接执行这个&#xff0c;下载下来的图片打不开 git clone https://huggingface.co/datasets/diffusers/dog-example 解决办法&#xff1a; 安装git lfs 1. curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash 2. sudo apt…

论文笔记:Adjusting for Autocorrelated Errors in Neural Networks for Time Series

2021 NIPS 原来的时间序列预测任务是根据预测论文提出用一阶自回归误差预测 一阶差分&#xff0c;类似于ResNet的残差思路&#xff1f;记为pred&#xff0c;最终的预测结果

zore-shot,迁移学习和多模态学习

1.zore-shot 定义&#xff1a;在ZSL中&#xff0c;某一类别在训练样本中未出现&#xff0c;但是我们知道这个类别的特征&#xff0c;然后通过语料知识库&#xff0c;便可以将这个类别识别出来。概括来说&#xff0c;就是已知描述&#xff0c;对未知类别&#xff08;未在训练集中…

Qsys介绍

文章目录 前言一、为什么需要Qsys1、简化了系统的设计流程2、Qsys涉及的技术 二、Qsys真身1、一种系统集成工具2、何为Nios II1、内核架构2、Nios II选型 三、Qsys设计涉及到的软件&工具四、总结五、参考资料 前言 Qsys是Altera下的一个系统集成工具&#xff0c;可用于搭建…

代码随想录算法训练营第三十天 | 单调栈系列复习

单调栈系列复习 每日温度未看解答自己编写的青春版重点题解的代码日后再次复习重新写 下一个更大元素 I未看解答自己编写的青春版重点题解的代码日后再次复习重新写 下一个更大元素II未看解答自己编写的青春版重点题解的代码日后再次复习重新写 接雨水未看解答自己编写的青春版…

idea模块的pom.xml被划横线,不识别的解决办法

目录 问题&#xff1a; 解决办法&#xff1a; 1.打开设置 2. 取消勾选 3.点击确认 4.解决 问题提出&#xff1a; 写shi山的过程中&#xff0c;给模块取错名字了&#xff0c;改名的时候不知道点到了什么&#xff0c;一个模块的pom.xml变成灰色了&#xff0…

3ds MAX粒子系统演示

其他各案例可以在视频中看到&#xff1a; 从左向右依次是&#xff1a; 粒子流源、喷射、雪、超级喷射、暴风雪、粒子阵列、粒子云 粒子系统

小研究 - JVM 垃圾回收方式性能研究(一)

本文从几种JVM垃圾回收方式及原理出发&#xff0c;研究了在 SPEC jbb2015基准测试中不同垃圾回收方式对于JVM 性能的影响&#xff0c;并通过最终测试数据对比&#xff0c;给出了不同应用场景下如何选择垃圾回收策略的方法。 目录 1 引言 2 垃圾回收算法 2.1 标记清除法 2.2…

iOS开发-实现获取下载主题配置动态切换主题

iOS开发-实现获取下载主题配置动态切换主题 iOS开发-实现获取下载主题配置更切换主题&#xff0c;主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。 比如新年主题风格&#xff0c;常见的背景显示红色氛围图片、tabbar显示新…

Visual Studio 设置默认编码格式为 UTF-8

1.添加高级保存选项 2.更改编码格式

客户端服务器通过Socket API通信流程 通过源码角度分析 三握手四挥手都过程的状态改变 及 例如accept()connect()具体做了什么

首先我们先说下网络编程API&#xff1a; 数据在网络上通信&#xff0c;通信的双方一个是 客户端&#xff0c; 一个是 服务器 更具体来说&#xff0c;不是 客户端和服务器这两个机器在 经由互联网 进行通信&#xff0c; 而是 客户端上的某一进程 与 服务器端的某一进程 进…

Java 单链表

链表基本介绍 链表在内存中的实际存储结构 链表的逻辑结构 单链表应用实例 代码实现 // 英雄节点&#xff0c;存储了英雄的信息 class HeroNode {public int id; // 英雄编号public String name; // 英雄名字public String nickName; // 英雄昵称public HeroNode next; // 指…

【系统软件01】devtoolset离线安装gcc

【系统软件01】devtoolset离线安装gcc 一、SCL简介二、SCL源安装三、离线下载devtoolset1、Developer Toolset2、下载devtoolset-93、压缩devtoolset-9 三、离线安装devtoolset-9(gcc9.3)1、解压devtoolset-9.tar.gz2、安装devtoolset-9 四、设置环境变量(使用gcc9.3)1、当前窗…

LeetCode547.Number-Of-Provinces<省份问题>

题目&#xff1a; 思路&#xff1a; 连通的部分加起来&#xff0c;然后总的 减去连通的部分。 但是很可惜 只能通过部分 似乎将st[i][j] st[j][i] 改变之后是可行的 但是实际上 1 2 连通后 2 1 确实是不会再加。 但是 2 3却还是在加一遍。 好吧。答案的思路是使用并查集。将…

lc209.长度最小的子数组

暴力破解&#xff1a;二次for循环遍历num[i]...num[j]&#xff0c;记录满足条件的最小长度 前缀和二分&#xff1a;前缀和降低计算num[i]...num[j]的时间复杂度 对前缀和数组中的每个数进行遍历&#xff0c;找到距离这个数满足条件的最小长度 前缀和数组单调递增&#xff0c;此…

蓝海卓越计费管理系统任意文件读取下载

……人哪&#xff0c;活着是这么的苦&#xff01;一旦你从幸福的彼岸被抛到苦难的此岸&#xff0c;你真是处处走头无路&#xff1b;而现在你才知道&#xff0c;在天堂与地狱之间原来也只有一步之遥&#xff01; 漏洞描述 蓝海卓越计费管理系统存在任意文件读取漏洞&#xff0…

pycharm写scrapy遇到的问题

目录 背景创建scrapy难受的开始指定类型修改模板并指定使用运行scrapy 背景 居然还有万能的pycharm解决不了的python程序&#xff1f;&#xff1f;&#xff1f; 创建scrapy 由于PyCharm中没有直接创建Scrapy项目的选项,所以使用命令行创建一个项目 安装scrapy pip install…

11、springboot项目启动时对容器中的bean进行延迟初始化

springboot项目启动时对容器中的bean进行延迟初始化 预初始化&#xff1a; Spring Boot在启动应用时&#xff0c;会启动Spring容器&#xff0c;当启动Spring容器时&#xff0c;Spring会自动初始化容器中所有的singleton Bean——这是默认行为 预初始化的好处&#xff1a; 1、项…