首页 > 编程语言 >数据结构与算法

数据结构与算法

时间:2024-05-31 09:45:01浏览次数:26  
标签:index 复杂度 算法 num 数组 数据结构 右侧 节点

  1. 时间复杂度

    常数操作包括加减乘除,以及从数组中取出一个值(因为直接计算偏移量,是一块连续的区域)

    注意:从list中取出一个值不是常数操作,因为需要遍历去找

    时间复杂度就是计算存在多少个常数操作

    且忽略低阶项,只要高阶项,且忽略高阶项的系数

  2. 通过亦或完成交换算法

    def swap():
        a = a ^ b
        b = a ^ b
        a = a ^ b
    

    为什么呢?

    假设 a = 甲 b = 乙

    a = a ^ b a = 甲 ^ 乙

    b = a ^b b = 甲乙 =甲 (两个相同的数亦或 = 0)(任何一个数亦或0都为它自己)

    a = a ^b a = 甲 ^ 乙^甲 = 乙

    前提是:a和b内存中的位置不可以相等(数组中相同位置)

    不建议使用

  3. 位运算取出最后一个1

    a & (~a + 1)

    一个数与上他的取反加一,就提取除了最后一位为1的数

  4. 排序

    • 冒泡排序:相邻位置的数进行比较,大的放到后面,比如,位置1的数与位置2的数比较,位置2的数与位置3的数比较,一轮下来找到最大的数,也就是最右的数,然后开始1-n-2的下一轮比较
    • 选择排序:遍历i到n-1找到最小值放入i位置上,i依次++
    • 插入排序:拿到一个数,位置为n,与前一个数(n-1)比较,比(n-1)位置上的数大则不交换,因为0-(n-1)一定有序,比(n-1)位置上的数小则交换,直至前面的数大于自己,或前方没有数
  5. 二分

    • 有序数组,是否存在某个数num
    • 有序数组,找到大于等于某个数num的最左位置:二分法,这个数的左侧一定是小于num的,右侧一定是等于或大于num的,以此为条件二分
    • 无序数组,找到其局部最小:局部最小一定是左侧是向下趋势的,即左侧的数比右侧的大;右侧也是向下趋势的,即右侧的数比左侧的大。先看两边,如果满足条件,再二分
  6. 归并排序

    二分,让左侧的数组与右侧的数组分别有序,再merge左侧数组与右侧数组

    merge的逻辑是:开辟一块新的空间存放排好序的help数组。左侧数组的i(i=0;i++)位置的数与右侧数组j(j=0;j++)位置的数比较,谁小就添加到下方help数组中,再i++或j++,再进行比较,直到一方越界,再将剩下的数全部拷贝到help中来。

    时间复杂度:O(NlogN)

    时间复杂度之所以优化了,是因为没有浪费排序的结果。比较选择排序而言,遍历一次只找到一个最小(或最大)的数,没有充分利用其的比较。

  7. 归并变形:求小和

    求一个数组中,比i小且位置在i左侧的数的和。遍历数组中所有的数的加和,即为小和

    也可转换需求,即求右侧比自己大的数的个数,然后乘自己。遍历数组中所有的数再加和,也为小和。

    找到右侧比自己大的数的个数,利用归并排序中的merge方法,如果左侧的数比右侧的数小,则小和sum+左侧的数*右侧排好序的个数,右侧排好序的个数通过下标很容易计算出来,然后将左侧的数放入help数组中。如果左侧的数与右侧的数相等,将右侧的数先copy到help数组中。这样才能知道有多少数比左侧的数大。如果左侧的数大,则将右侧数copy到help中,指针右移。

  8. 荷兰国旗问题

    • 问题一:给定一个num,使小于它的数放在左边,大于它的数放到右边,不要求有序。时间复杂度O(n),空间复杂度O(1)

      def dutch_flag_reduce(_arr, _num):
          index = 0
          jx = -1
          while index < len(_arr):
              #[index]<=num时,[index]与jx的下一个数交换,jx+1,index继续遍历
              if _arr[index] <= _num:
                  swap(_arr, jx + 1, index)
                  jx += 1
              #[index]>num时,index继续遍历
              index += 1
      
    • 问题二:在问题一的基础上,使小于它的数放在左边,大于它的数放到右边,等于num的数放在中间。

      def dutch_flag(_arr, _num):
          index = 0
          left = -1
          right = len(_arr)
          while index < right:
              #[index]<num时,[index]与left的下一个数交换,left+1,index继续遍历
              if _arr[index] < _num:
                  swap(_arr, left + 1, index)
                  left += 1
                  index += 1
              #[index]=num时,index继续遍历
              elif _arr[index] == _num:
                  index += 1
              #[index]>num时,[index]与right的上一个数交换,right-1,index不变。因为需要继续比较当前index的交换来的新数
              elif _arr[index] > _num:
                  swap(_arr, right - 1, index)
                  right -= 1 
      
  9. 快速排序

    • 方案一:以数组中最后一个数为num,对前面的数采用荷兰国旗问题一的解法,最后将num与大于区域的第一个交换。然后递归其左侧和右侧。

    • 方案二:采用荷兰国旗问题二的解法,再对大于区域和小于区域递归,等于区域不动。对比方案一,少了等于区域那部分的递归,稍微快一些。

    • 时间复杂度:如果每次num都正好在数组的中间时,符合master公式,时间复杂度O(nlogN)。

      而 如果每次num正好在一侧,相当于一侧的递归范围为0时,符合等差数列,时间复杂度(On^2)

  10. 堆中存在heapsize维护堆的范围

    是一个近似完全二叉树的二叉树,每个父节点都大于等于他的子节点,叫做大根堆

    当已知一个位置i,他的父节点为(i-1)/2,左子节点为2i+1,右子节点2i+2

    大根堆操作:

    • heapInsert:

      当用户给我数字时,如何维持大根堆。

      与父节点比较,若大于父节点,则交换,继续与当前父节点比较,若大于父节点,则交换,直至数组越界,或不大于了

    • heapify:

      去除当前大根堆最大节点,将数组最后一个数放到该父节点上,如何维护大根堆

      左孩子与右孩子比较,最大的一个与父节点比较,若大于父节点则与父节点交换。

      交换后该节点继续与其左孩子与右孩子比较

  11. 堆排序

    • 当那个heapsize为1时,将0、1位置的数heappInsert,heapsize++,接着heapInsert构建出大根堆结构

      将最后位置的数与0位置的数交换,然后进行heapify,heapsize--,直至heapsize = 0,排序成功

      时间复杂度 O(NlogN) 空间复杂度O(1)

    • 反正第一步也是维护大根堆结构,可以用heapify。从数组最后的节点做heapify,依次向前。O(NlogN)

  12. 堆扩展算法

    一个几乎有序的数组,几乎有序是指,如果把数组排好序的话,每个元素的移动距离不超过k,且k相对与数组来说比较小

    堆排序,对i与i+k之间的数维护成小根堆,放在i位置上,接着i++,对i+1与i+k+1位置上的数维护成小根堆,最后将剩余的小根堆中的数依次停好

  13. 堆结构

    每个编程语言中都有堆结构,其内部结构为数组,堆长度通过heapsize控制。当数组长度不够时,会2n扩容。

    编程语言中的堆结构不建议手写修改一个数,更改堆结构。需要更改堆结构时,手写堆。

    系统中的堆结构建议是你给它一个数,他给你一个数。

    java中只有小根堆,使用比较器改成大根堆

  14. 计数排序

    准备一个辅助数组,他的下标位置上的数代表当前排序数组中存在多少该下标的数,最后将其依次展开。

    适合有范围的数据状况,比如年龄排序,辅助数组的范围可以是(0,200)

  15. 基数排序

    排序一组十进制的数,准备10个桶,从个位数依次进桶,比如11进入1号桶,56进入6号桶,36进入6号桶,接着依次倒出,先进先出。接着排序十位,然后百位,倒出来后就已经排好序了。

    原理是先排个位数,然后排十位。因为位数越高优先级越高。

  16. 基数排序代码层面优化

    准备一个help数组与原数组长度一致,准备一个原数组位数长度的count数组。

    遍历原数组,将其最后一位的词频记录到count数组中,将count数组每一index上的数与前面的数累加

    例:原count数组为:0,1,1,4,6。转换为:0,1,2,6,12

    含义为原数组个位数<=当前index的数有几个

    接着从后遍历原数组,如果数字为22,则看count数组上3位置的数有4个,说明它前面存在3个<=它的数,所以它应该在第4个位置上(help数组),接着4--。继续向前遍历。当前数组遍历完成。相当于对个位数进行了一次入桶。将help数组转移到原数组中,相当于出桶。

    然后继续遍历十位上的数。

标签:index,复杂度,算法,num,数组,数据结构,右侧,节点
From: https://www.cnblogs.com/qbxyzzjw/p/18223835

相关文章

  • C++数据结构之:栈Stack
    摘要:  it人员无论是使用哪种高级语言开发东东,想要更高效有层次的开发程序的话都躲不开三件套:数据结构,算法和设计模式。数据结构是相互之间存在一种或多种特定关系的数据元素的集合,即带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系,分为逻辑结构和存储......
  • 【算法】范围尝试模型、已有字符串添加最少字符使其成为回文字符串
    1.概述给定一个字符串str,如果可以在str的任意位置添加宇符,请返回在添加字符最少的情況下,让str整体都是回文字符串的一种结果。【举例】str="ABA"str本身就是回文串,不需要添加字符,所以返回"ABA"str="AB"可以在’A'之前添加’B'使str整体都是回文串,故可以返回"BAB"......
  • 使用Java实现线性回归算法
    线性回归算法原理线性回归的基本思想是通过一条直线来拟合数据点,使得数据点到这条直线的距离平方和最小。其数学表达式为:y=β......
  • C语言贪心算法——解硬币
    题目:有1元,5元,10元,100元,500元的硬币各从c1枚,c5枚,c10枚,c50枚,c100枚,c500枚,现在要用这些硬币支付A元,最少需要多少枚硬币输入:第一行有六个数字,分别代表从小到大6种面值的硬币的个数:第二行为A案例:输入:321302620输出:6#include<stdio.h>intmain(){ intnumber[6]......
  • 算法金 | 详解过拟合和欠拟合!性感妩媚 VS 大杀四方
    大侠幸会,在下全网同名「算法金」0基础转AI上岸,多个算法赛Top「日更万日,让更多人享受智能乐趣」今天我们来战过拟合和欠拟合,特别是令江湖侠客闻风丧胆的过拟合,简称过儿,Emmm过儿听起来有点怪怪的1.楔子机器学习模型是一种能够从数据中学习规律并进行预测的算法。......
  • 杂数据结构选做
    杂数据结构选做持续更新ing...更新多少取决于我卷了多少似乎都是比较基础的东西,但是我数据结构太菜了,没办法╮(╯_╰)╭#9016.CodeChefMINXORSEG有两种做法,我敲的后一种第一种先不考虑范围问题,考虑现在有三个点\(u,v,w\),若它们的\(lcp\)为\(l\),那么考虑第\(l+1\)位,根据......
  • 代码随想录算法训练营第第23天 | 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索
    修剪二叉搜索树这道题目比较难,比添加增加和删除节点难的多,建议先看视频理解。题目链接/文章讲解:https://programmercarl.com/0669.修剪二叉搜索树.html视频讲解:https://www.bilibili.com/video/BV17P41177ud/***@param{TreeNode}root*@param{number}low*@pa......
  • A*算法求解八数码问题
    一、问题描述:A*算法是一种启发式图搜索算法,其特点在于对估价函数的定义上。对于一般的启发式图搜索,总是选择估价函数f值最小的节点作为扩展节点。因此,f是根据需要找到一条最小代价路径的观点来估算节点的,所以,考虑每个节点n的估价函数值为两个分量:f(n)=g(n)+h(n),从起始节点......
  • 基于DCT变换和位平面分解的数字水印嵌入提取算法matlab仿真
    1.算法运行效果图预览    2.算法运行软件版本matlab2022a 3.算法理论概述    基于离散余弦变换(DiscreteCosineTransform,DCT)和位平面分解(Bit-PlaneDecomposition)的数字水印嵌入与提取算法,是一种结合了频域与空域特性的稳健数字水印技术。该方法利......
  • 计算机算法中的数字表示法——定点数
    目录1.前言2.什么是定点数3.定点数如何去表示数字4.定点数表示法的局限性1.前言前面一篇文章讲了计算机中的数字表示法:原码、补码和反码,这一篇文章开始进行定点数的讲解。2.什么是定点数定点数,从字面意思上理解就是小数点位置固定,如下图所示:数字既包括整数,又包括......