977有序数组的平方,排序算法复习,189轮转数组

https://leetcode-cn.com/study-plan/algorithms/?progress=lv45wk7

有序数组的平方

排序复习

插入排序

插入排序是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

算法描述
  1. 把待排序的数组分成已排序和未排序两部分,初始的时候把第一个元素认为是已排好序的。
  2. 从第二个元素开始,在已排好序的子数组中寻找到该元素合适的位置并插入该位置。
  3. 重复上述过程直到最后一个元素被插入有序子数组中。

由于只需要找到不大于当前数的位置而并不需要交换,因此,直接插入排序是稳定的排序方法。

算法实现
func sortedSquares(nums []int) []int {ans:=make([]int,len(nums))ans[0]=nums[0]*nums[0]var i,j intfor i=1;i<len(nums);i++ {temp:=nums[i]*nums[i]for j=i-1;j>=0;j--{if temp < ans[j]{ans[j+1]=ans[j]}else{break}}ans[j+1]=temp}return ans
}

冒泡排序

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

算法描述
  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  3. 针对所有的元素重复以上的步骤,除了最后一个;
  4. 重复步骤1~3,直到排序完成。

在相邻元素相等时,它们并不会交换位置,所以,冒泡排序是稳定排序。

算法实现
func sortedSquares(nums []int) []int {ans:=make([]int,len(nums))var i,j intn:=len(nums)for k,val:=range nums{ans[k]=val*val}for i=n-1;i>0;i-- {for j=0;j<i;j++{if ans[j]>ans[j+1]{temp:=ans[j]ans[j]=ans[j+1]ans[j+1]=temp}}}return ans
}

在数据完全有序的时候展现出最优时间复杂度,为O(n)。其他情况下,几乎总是O(n2n^2n2)。因此,算法在数据基本有序的情况下,性能最好。

要使算法在最佳情况下有O(n)复杂度,需要做一些改进,增加一个flag的标志,当前一轮没有进行交换时,说明数组已经有序,没有必要再进行下一轮的循环了,直接退出。

func sortedSquares(nums []int) []int {ans:=make([]int,len(nums))var i,j intn:=len(nums)for k,val:=range nums{ans[k]=val*val}for i=n-1;i>0;i-- {flag:=falsefor j=0;j<i;j++{if ans[j]>ans[j+1]{temp:=ans[j]ans[j]=ans[j+1]ans[j+1]=tempflag=true}}if(flag==false){break}}return ans
}

选择排序

算法描述

选择排序是一种简单直观的排序算法,它也是一种交换排序算法,和冒泡排序有一定的相似度,可以认为选择排序是冒泡排序的一种改进。

  1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
  2. 从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

用数组实现的选择排序是不稳定的,用链表实现的选择排序是稳定的。

不过,一般提到排序算法时,大家往往会默认是数组实现,所以选择排序是不稳定的。

算法实现
func sortedSquares(nums []int) []int {ans:=make([]int,len(nums))var i,j,temp intn:=len(nums)for k,val:=range nums{ans[k]=val*val}for i=0;i < n-1;i++ {min:=ifor j=i+1;j<n;j++{if ans[j]<ans[min]{min=j}}if min!=i{temp=ans[min]ans[min]=ans[i]ans[i]=temp}}return ans
}

归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

算法描述

因为我们在遇到相等的数据的时候必然是按顺序“抄写”到辅助数组上的,所以,归并排序同样是稳定算法。

递归法(Top-down)
  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  4. 重复步骤3直到某一指针到达序列尾
  5. 将另一序列剩下的所有元素直接复制到合并序列尾
迭代法(Bottom-up)

原理如下(假设序列共有n个元素):

  1. 将序列每相邻两个数字进行归并操作,形成ceil(n/2)个序列,排序后每个序列包含两/一个元素
  2. 若此时序列数不是1个则将上述序列再次归并,形成ceil(n/4)个序列,每个序列包含四/三个元素
  3. 重复步骤2,直到所有元素排序完毕,即序列数为1
算法实现
func mergesort(result_left,result_right []int) []int{result := make([]int, 0)i, j := 0, 0l, r := len(result_left), len(result_right)for i<l && j<r{if result_left[i] > result_right[j]{result = append(result, result_right[j])j++}else {result = append(result, result_left[i])i++}}result = append(result, result_right[j:]...)result = append(result, result_left[i:]...)return result
}
func merge(ans []int) []int {var mid intvar result,result_left,result_right []intif len(ans)<2{return ans}mid=len(ans)/2result_left=merge(ans[0:mid])result_right=merge(ans[mid:])result=mergesort(result_left,result_right)return result
}
func sortedSquares(nums []int) []int {ans:=make([]int,len(nums))for k,v:=range nums{ans[k]=v*v}ans=merge(ans)return ans
}

快排

快速排序是一个知名度极高的排序算法,其对于大数据的优秀排序性能和相同复杂度算法中相对简单的实现使它注定得到比其他算法更多的宠爱。

算法描述
  1. 从数列中挑出一个元素,称为"基准"(pivot)
  2. 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
算法实现
func sort(arr []int, low int, high int) {if high <= low {return}pivot:= partition(arr, low, high)sort(arr, low, pivot-1)sort(arr, pivot+1, high)
}
func partition(arr []int, low int, high int) int {pivot:=arr[low]for low<high {for arr[high]>=pivot&& low<high {high--}arr[low]=arr[high]for arr[low] <= pivot&&low<high {low++}arr[high]=arr[low]}arr[low]=pivotreturn low
}
func sortedSquares(nums []int) []int {ans:=make([]int,len(nums))for k,v:=range nums{ans[k]=v*v}sort(ans,0,len(nums)-1)return ans
}

go语言调库

sort库中Ints函数
func Ints(a []int)
Ints函数将a排序为递增顺序

func sortedSquares(nums []int) []int {ans:=make([]int,len(nums))for i,val:=range nums{ans[i]=val*val}sort.Ints(ans)return ans
}

双指针

显然,如果数组中的所有数都是非负数,那么将每个数平方后,数组仍然保持升序;如果数组中的所有数都是负数,那么将每个数平方后,数组会保持降序。

这样一来,如果我们能够找到数组中负数与非负数的分界线,那么就可以用类似「归并排序」的方法了。

func sortedSquares(nums []int) []int {n := len(nums)//因存在全为正数的情况lastNegIndex := -1for i := 0; i < n && nums[i] < 0; i++ {lastNegIndex = i}ans := make([]int, 0, n)for i, j := lastNegIndex, lastNegIndex+1; i >= 0 || j < n; {//全为正数if i < 0 {ans = append(ans, nums[j]*nums[j])j++} else if j == n {//全为负数ans = append(ans, nums[i]*nums[i])i--} else if nums[i]*nums[i] < nums[j]*nums[j] {ans = append(ans, nums[i]*nums[i])i--} else {ans = append(ans, nums[j]*nums[j])j++}}return ans
}

同样地,我们可以使用两个指针分别指向位置 0 和 n-1,每次比较两个指针对应的数,选择较大的那个逆序放入答案并移动指针。这种方法无需处理某一指针移动至边界的情况。

轮转数组

额外数组

我们可以使用额外的数组来将每个元素放至正确的位置。
用 n 表示数组的长度,我们遍历原数组,将原数组下标为 i 的元素放至新数组下标为(i+k)modn(i+k)\bmod n(i+k)modn的位置,最后将新数组拷贝至原数组即可。

func rotate(nums []int, k int)  {newNums := make([]int, len(nums))for i, v := range nums {newNums[(i+k)%len(nums)] = v}copy(nums, newNums)
}

数组翻转

该方法基于如下的事实:当我们将数组的元素向右移动 k次后,尾部kmodnk\ mod\ nk mod n 个元素会移动至数组头部,其余元素向后移动 kmodnk\ mod\ nk mod n个位置。

该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的kmodnk\ mod\ nk mod n 个元素就被移至数组头部,然后我们再翻转 [0,kmodn−1][0, k\bmod n-1][0,kmodn−1]区间的元素和 [kmodn,n−1][k\bmod n, n-1][kmodn,n−1] 区间的元素即能得到最后的答案。

func reverse(a []int) {for i, n := 0, len(a); i < n/2; i++ {a[i], a[n-1-i] = a[n-1-i], a[i]}
}func rotate(nums []int, k int) {k %= len(nums)reverse(nums)reverse(nums[:k])reverse(nums[k:])
}

力扣算法学习计划打卡:第二天相关推荐

  1. 力扣算法学习计划打卡:第五天

    876链表的中间结点,19删除链表的倒数第N个节点 链表的中间结点 用两个指针 slow 与 fast 一起遍历链表.slow 一次走一步,fast 一次走两步.那么当 fast 到达链表的末尾时,s ...

  2. 力扣算法学习计划打卡:第七天

    733 图像渲染,695 岛屿的最大面积 图像渲染 广度优先搜索 var(dx = []int{1,0,-1,0}dy = []int{0,1,0,-1} ) func floodFill(image ...

  3. 力扣算法学习计划打卡:第六天

    3无重复字符的最长子串,567 字符串的排列 无重复字符的最长子串 滑动窗口/双指针 func max(a,b int)int{if a<b{return b}return a }func le ...

  4. 力扣算法学习计划打卡:第八天

    617.合并二叉树,116.填充每个节点的下一个右侧节点指针 合并二叉树 深度优先搜索 /*** Definition for a binary tree node.* type TreeNode s ...

  5. 力扣算法学习计划打卡:第三天

    283 移动零,167. 两数之和 II - 输入有序数组 移动零 不能复制数组,考虑计数0的个数,当前数组元素前存在counts个0元素,该数组元素向前移动counts个值,最后将counts个0放 ...

  6. 力扣算法学习计划打卡:第一天

    704二分查找,278第一个错误版本,35搜索插入位置 二分查找 https://leetcode-cn.com/study-plan/algorithms/?progress=lv45wk7 顺序查 ...

  7. 力扣算法学习计划打卡:第四天

    344反转字符串,557. 反转字符串中的单词 III 反转字符串 双指针,分别指向字符数组的头和尾,交换后,两个指针同时向中间移动 func reverseString(s []byte) {for ...

  8. 力扣算法学习(十四)

    最小路径和 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例 1: 输入:grid = ...

  9. 力扣算法学习(十二)

    斐波那契数 斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 .该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) = 0,F(1) = 1 F(n) ...

最新文章

  1. @所有人,CSDN 粉丝专属福利来啦!
  2. C言语选择排序算法及代码
  3. C 将长型整数转换为字符串
  4. 鸿蒙上海开发者日直播,华为鸿蒙 OS 开发者日于 4月17 日上海举行
  5. 实现一个 DFA 正则表达式引擎 - 4. DFA 的最小化
  6. 可惜Java中没有yield return
  7. 2023届IC实习小结
  8. UBI文件系统和镜像的制作及分区挂载说明
  9. zabbix监控redis
  10. ORA-00845 方案解决
  11. Python的基本数据类型(1)
  12. 切割图形_激光切割机氧气切碳钢板过烧怎么解决?这几点一定要注意!
  13. python爬取安居客房屋价格用地图表示出来
  14. 解决 注册谷 歌 邮 箱 gmail 手机号无法用于验证
  15. 缓冲区,缓存,fflush(stdin)如何使用?
  16. 计算机专业该如何找实习工作?迷茫、不知所措的你值得一看~
  17. echart图表-刷新界面.初始化时默认显示hover提示内容
  18. 计算机卸载应用程序的步骤,Win10系统下卸载应用程序的步骤
  19. The server time zone value ‘�й���׼ʱ��’ is unrecognized or represents more than one time zone. You mu
  20. 塔夫斯大学计算机专业,Tufts的ECE「塔夫茨大学电气与计算机工程系」

热门文章

  1. 华为Java面试真题解析,都是精髓!
  2. 支付宝转账到银行卡API接口解析
  3. 计算机培训校本研修心得,校本研修培训心得体会(精选5篇)
  4. python报错 ‘utf-8‘ codec can‘t encode characters in position xxxx-xxxx: surrogates not allowed
  5. 重学Elasticsearch第6章 : SpringBoot整合RestHighLevelClient
  6. csma最短帧长_(CSMA CD)的最小帧长计算
  7. 国内主流CMS、SNS、商城等建站系统汇总
  8. CSDN博客积分规则和获取积分方法
  9. python爬虫去哪儿网_用python爬虫爬取去哪儿4500个热门景点,看看国庆不能去哪儿...
  10. 移动H5前端性能优化指南(转自ISUX)