文章目录

  • 引言
  • 基本概念
    • 时间复杂度
      • 常数
    • 空间复杂度
  • 排序算法
    • 冒泡排序
      • 算法
      • 代码
    • 选择排序
      • 算法
      • 代码
    • 插入排序
      • 算法
      • 代码
  • 二分查找法
    • 算法
    • 常见应用
    • 代码
  • 异或运算
    • 算法
    • 常见应用
    • 算法应用:136. 只出现一次的数字
    • 算法应用:389.找不同
    • 算法应用:寻找2个奇数次的数
  • 对数器

引言

  总结算法基本概念以及常见的算法思路。

基本概念

时间复杂度

  1. 在表达式中,只需要高阶项,去除低阶项和高阶项的系数,剩余部分f(n),则时间复杂度为O(f(n))

常数

  1. 常数操作:若一个操作和样本的数据量无关,每次都是固定时间内完成操作,则成为常数操作。

空间复杂度

排序算法

冒泡排序

算法

大的往后冒泡:

  1. 将序列中所有元素两两比较,将最大的数往后交换,冒泡到最后面。
  2. 将剩余序列中所有元素两两比较,将最大的数往后交换,冒泡到最后。
  3. 重复第2步,直到只剩下一个数。

代码

时间复杂度:O(n^2)

package com.test.selfcoding.algorithm.sort;import com.test.selfcoding.utils.RandomArrayUtil;import java.util.Arrays;/*** @ClassNAME BubbleSort* @Description TODO* @Author Andya* @Version 1.0*/
public class BubbleSort {public static void bubbleSort1(int[] arr) {/*1. 将序列中所有元素两两比较,将最大的数往后交换,冒泡到最后面n-1。2. 将剩余序列中所有元素两两比较,将最大的数往后交换,冒泡到上一次的最后前一个数n-1-i。3. 重复第2步,直到只剩下一个数。*/int count = 0;// 第一层循环i: 0 ~ n-1for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {if (arr[j] > arr[j + 1]) {swap(arr, j, j + 1);}count++;}}System.out.println("times: " + count);}public static void bubbleSort2(int[] arr) {/*1. 将序列中所有元素两两比较,将最大的数往后交换,冒泡到最后面n-1。2. 将剩余序列中所有元素两两比较,将最大的数往后交换,冒泡到上一次的最后前一个数n-1-i。3. 重复第2步,直到只剩下一个数。*/int count = 0;// 第一层循环i: 0 ~ n-1for (int i = 0; i < arr.length - 1; i++) {boolean flag = true;// 循环后若发现已经排序完毕,则无需进入交换for (int j = 0; j < arr.length - 1 - i; j++) {if (arr[j] > arr[j + 1]) {swap(arr, j, j + 1);flag = false;}count++;}//无任何交换,发现是顺序的,直接退出if (flag) {break;}}System.out.println("times: " + count);}public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void main(String[] args) {//        int[] arr = {1, 2, 5, 2, 3, 6, 6, 8, 7, 4};
//        bubbleSort1(arr);
//        System.out.println(Arrays.toString(arr));int[] arr = {1, 2, 3, 4, 5, 6, 6, 7, 8};bubbleSort1(arr);System.out.println(Arrays.toString(arr));bubbleSort2(arr);System.out.println(Arrays.toString(arr));int[] arr1 = RandomArrayUtil.generateRandomArray(1000, 1000);int[] arr2 = RandomArrayUtil.copyArray(arr1);bubbleSort1(arr1);System.out.println(Arrays.toString(arr1));bubbleSort2(arr2);System.out.println(Arrays.toString(arr2));}}//结果
times: 36
[1, 2, 3, 4, 5, 6, 6, 7, 8]
times: 8
[1, 2, 3, 4, 5, 6, 6, 7, 8]
times: 8646
[-860, -843, -776, -760, -731, -696, -694, -694, -674, -659, -658, -655, -651, -641, -617, -604, -558, -556, -547, -544, -540, -524, -524, -519, -512, -496, -463, -439, -429, -407, -401, -362, -346, -335, -303, -291, -290, -277, -271, -267, -248, -239, -231, -228, -227, -221, -221, -219, -202, -181, -178, -153, -143, -142, -134, -113, -101, -75, -68, -50, -33, -33, -22, -16, 6, 16, 27, 36, 37, 41, 47, 57, 67, 75, 91, 96, 109, 119, 135, 146, 152, 159, 160, 175, 176, 192, 202, 211, 217, 218, 281, 281, 299, 313, 334, 354, 359, 359, 375, 377, 404, 409, 441, 445, 446, 459, 459, 472, 478, 488, 510, 514, 532, 553, 567, 580, 582, 583, 612, 635, 643, 661, 662, 680, 682, 693, 715, 742, 790, 792, 795, 814]
times: 8510
[-860, -843, -776, -760, -731, -696, -694, -694, -674, -659, -658, -655, -651, -641, -617, -604, -558, -556, -547, -544, -540, -524, -524, -519, -512, -496, -463, -439, -429, -407, -401, -362, -346, -335, -303, -291, -290, -277, -271, -267, -248, -239, -231, -228, -227, -221, -221, -219, -202, -181, -178, -153, -143, -142, -134, -113, -101, -75, -68, -50, -33, -33, -22, -16, 6, 16, 27, 36, 37, 41, 47, 57, 67, 75, 91, 96, 109, 119, 135, 146, 152, 159, 160, 175, 176, 192, 202, 211, 217, 218, 281, 281, 299, 313, 334, 354, 359, 359, 375, 377, 404, 409, 441, 445, 446, 459, 459, 472, 478, 488, 510, 514, 532, 553, 567, 580, 582, 583, 612, 635, 643, 661, 662, 680, 682, 693, 715, 742, 790, 792, 795, 814]

选择排序

算法

  1. 第一层循环先定义一个记录最小元素的下标,然后第二层循环一次后面的数组,找到最小的元素,最后将它放到前面排序好的序列。

代码

时间复杂度:O(n^2),空间复杂度:O(1)

package com.test.selfcoding.algorithm;import java.util.Arrays;/*** @ClassNAME SelectionSort* @Description TODO* @Author Andya* @Date 2022/5/21 11:30* @Version 1.0*/
public class SelectionSort {public static void selectionSort(int[] arr) {//空或者长度小于等于1,则直接返回,无需排序if (arr == null || arr.length < 2) {return;}for (int i = 0; i < arr.length - 1; i++) {int minIndex = i;// i ~ n-1上找到最小值下标for (int j = i + 1; j < arr.length; j++) {minIndex = arr[j] < arr[minIndex] ? j : minIndex;}if (minIndex != i) {swap(arr, i, minIndex);}}}private static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}public static void main(String[] args) {int[] arr = {1,5,3,7,8,4,2,1,2,6};selectionSort(arr);System.out.println(Arrays.toString(arr));}}

插入排序

算法

  1. 将第一个数和第二个数排序,构成一个有序序列;
  2. 将后面第三个数插入进去,构成一个新的有序序列;
  3. 依次对第四个数、第五个数……直到最后一个数,重复第二步。

代码

时间复杂度:O(n^2),空间复杂度:O(1)

package com.test.selfcoding.algorithm;import java.util.Arrays;/*** @ClassNAME InsertionSort* @Description TODO* @Author Andya* @Version 1.0*/
public class InsertionSort {public static void insertionSort(int[] arr) {if (arr == null || arr.length < 2) {return;}for (int i = 1; i < arr.length; i++) {// 让第 0~i 有序for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {//左边的大于右边的,则左右换位置,并且右边的一直往前比较,一直到下标为0或数比左边的大时就不用进入循环了。swap(arr, j, j + 1);}}}private static void swap(int[] arr, int j, int i) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void main(String[] args) {int[] arr = {1, 2, 5, 3, 4, 2, 7, 6, 9, 8};insertionSort(arr);System.out.println(Arrays.toString(arr));}
}

二分查找法

算法

常见应用

  1. 在一个有序数组中,找某个数是否存在。
  2. 在一个有序数组中,找大于等于某个数最左侧的位置。
  3. 局部最小值问题。(此处就不一定是有序, 找中间数,若是局部最小值,则返回,若不是,左侧相邻的数和右侧相邻的数谁小,则二分到此区间必定有局部最小)

代码

时间复杂度:O(logN)


异或运算

算法

a ^ 0 == a
a ^ a == 0
满足交换律和结合律。

常见应用

  1. 不用额外的变量交换两个数。
  2. 一个数组中有1个数出现了奇数次,其他数都出现偶数次,查找这1个数。
  3. 一个数组中有2个数出现了奇数次,其他数都出现偶数次,查找这2个数。

算法应用:136. 只出现一次的数字

136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?示例 1:输入: [2,2,1]
输出: 1
示例 2:输入: [4,1,2,1,2]
输出: 4

这种题目,我们就可以使用异或的如下两个特性进行求解:

  1. 一个数与本身异或,结果总是为 0
  2. 一个数与0异或,结果总是其自身
package com.test.selfcoding.algorithm;/*** @ClassNAME SingleNumber* @Description TODO* @Author Andya* @Date 2022/5/21 17:01* @Version 1.0*/
public class SingleNumber {public static int singleNumber(int[] nums) {int ans = nums[0];for (int i = 1; i < nums.length; i++) {//使用异或^运算//1. 一个数与本身异或,结果总是为0//2. 一个数与0异或,结果总是其自身ans = ans ^ nums[i];}return ans;}public static void main(String[] args) {int[] nums = {4,1,2,1,2};System.out.println(singleNumber(nums));   //结果:4}}

算法应用:389.找不同

389. 找不同

package com.test.selfcoding.algorithm;/*** @ClassNAME FindTheDifference* @Description TODO* @Author Andya* @Date 2022/5/21 17:25* @Version 1.0**/
public class FindTheDifference {/*** 使用异或* @param s* @param t* @return*/public static char findTheDifferenceWithXOR(String s, String t) {int ans = 0;for (int i = 0; i < s.length(); i++) {ans ^= s.charAt(i);}// 此时ans将s字符串中的所有字符拼接起来了for (int j = 0; j < t.length(); j++) {ans ^=  t.charAt(j);}return (char)ans;}/*** 使用位计数法* @param s* @param t* @return*/public static char findTheDifferenceWithCount(String s, String t) {// 26个字母大小的数组int[] letter = new int[26];for (int i = 0; i < s.length(); i++) {char sChar = s.charAt(i);//对应字符位置的数值+1letter[sChar - 'a']++;}for (int j = 0; j < t.length(); j++) {char tChar = t.charAt(j);//对应字符位置的数值-1letter[tChar - 'a']--;//找到负数的则为不同if (letter[tChar - 'a'] < 0) {return tChar;}}return ' ';}/*** 使用ASCII码计算* @param s* @param t* @return*/public static char findTheDifferenceWithASCII(String s, String t) {//将字符串s和t中每个字符的ASCII码的值求和,得到asciiS和asciiTint asciiS = 0, asciiT = 0;for (int i = 0; i < s.length(); i++) {asciiS += s.charAt(i);}for (int j = 0; j < t.length(); j++) {asciiT += t.charAt(j);}return (char) (asciiT - asciiS);}public static void main(String[] args) {String s = "abcdef";String t = "abcdfeg";System.out.println(findTheDifferenceWithXOR(s, t));System.out.println(findTheDifferenceWithCount(s, t));System.out.println(findTheDifferenceWithASCII(s, t)); //结果:g}}

算法应用:寻找2个奇数次的数

package com.test.selfcoding.algorithm;import java.util.Arrays;/*** @ClassNAME Find2OddNumbers* @Description TODO* @Author Andya* @Date 2022/5/21 21:51* @Version 1.0*/
public class Find2OddNumbers {//寻找一个数组中仅有的2个奇数次的数,假设a,b,c,c,d,d,则a和b即为要找的结果public static int[] find2OddNumbers(int[] arr) {//eor = a ^ bint eor = 0;for (int cur : arr) {eor ^= cur;}//若res1 = b 则,res2 = eor ^ res1//找到二进制最右边的1,取非,加1,再与自身// eor =   111010010// ~eor =  000101101//~eor+1 = 000101110//eor & (~eor+1) = 000000010int right = eor & (~eor + 1);int onlyOne = 0;for (int cur : arr) {//取一半,此二进制位为0或者为1,即为一半if ((cur & right) == 1) {onlyOne ^= cur;}}return new int[] {onlyOne, eor ^ onlyOne} ;}public static void main(String[] args) {int[] arr = new int[] {1, 2, 3, 4, 2, 1, 3, 5, 4, 6, 7, 7};System.out.println(Arrays.toString(find2OddNumbers(arr))); //结果:[5,6]}}

对数器

package com.test.selfcoding.algorithm;import java.util.Arrays;/*** @ClassNAME SelectionSort* @Description TODO* @Author Andya* @Date 2022/5/21 11:30* @Version 1.0*/
public class SelectionSort {public static void selectionSort(int[] arr) {//空或者长度小于等于1,则直接返回,无需排序if (arr == null || arr.length < 2) {return;}for (int i = 0; i < arr.length - 1; i++) {int minIndex = i;// i ~ n-1上找到最小值下标for (int j = i + 1; j < arr.length; j++) {minIndex = arr[j] < arr[minIndex] ? j : minIndex;}if (minIndex != i) {swap(arr, i, minIndex);}}}private static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}//for test: 对数器 generate random arraypublic static int[] generateRandomArray(int maxSize, int maxValue) {// Math.random() -> [0,1) 所有的小数,等概率返回一个// Math.random() * N -> [0,N) 所有的小数,等概率返回一个// (int)(Math.random() * N -> [0,N-1]所有的整数,等概率返回一个//长度随机int[] arr = new int[(int) ((maxSize + 1) * Math.random())];for (int i = 0; i < arr.length; i++) {arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());}return arr;}// for test: copy arraypublic static int[] copyArray(int[] arr) {if (arr == null) {return null;}//新建一个数组int[] res = new int[arr.length];for (int i = 0; i < arr.length; i++) {res[i] = arr[i];}return res;}// for test: is equalspublic static boolean isEqual(int[] arr1, int[] arr2) {if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {return false;}if (arr1 == null && arr2 == null) {return true;}if (arr1.length != arr2.length) {return false;}for (int i = 0; i < arr1.length; i++) {if (arr1[i] != arr2[i]) {return false;}}return true;}// for test: sortArraypublic static void sortArray(int[] arr) {Arrays.sort(arr);}public static void main(String[] args) {//        int[] arr = {1, 5, 3, 7, 8, 4, 2, 1, 2, 6};
//        selectionSort(arr);
//        System.out.println(Arrays.toString(arr));int testTime = 600000;int maxSize = 100;int maxValue = 100;boolean succeed = true;for (int i = 0; i < testTime; i++) {int[] arr1 = generateRandomArray(maxSize, maxValue);int[] arr2 = copyArray(arr1);selectionSort(arr1);sortArray(arr2);if (!isEqual(arr1, arr2)) {System.out.println(Arrays.toString(arr1));System.out.println(Arrays.toString(arr2));succeed = true;break;}}System.out.println("result: " + (succeed ? "succeeded" : "failed!"));int[] arr = generateRandomArray(maxSize, maxValue);System.out.println(Arrays.toString(arr));selectionSort(arr);System.out.println(Arrays.toString(arr));}}

算法—学习、练习和总结相关推荐

  1. 拿下斯坦福和剑桥双offer,00后的算法学习之路

    董文馨,00后,精通英语,西班牙语.斯坦福大学计算机系和剑桥大学双Offer,秋季将进入斯坦福大学学习. 10岁开始在国外上学:12岁学Scratch: 13岁学HTML & CSS: 14岁 ...

  2. 好久没有看到这么有建设性德文章,由衷地赞叹《知其所以然地学习(以算法学习为例)》-By 刘未鹏(pongba)

    知其所以然地学习(以算法学习为例) By 刘未鹏(pongba) C++的罗浮宫(http://blog.csdn.net/pongba) Updated(2008-7-24):更新见正文部分,有标注 ...

  3. 原创 | 初学者友好!最全算法学习资源汇总(附链接)

    在计算机发展飞速的今天,也许有人会问,"今天计算机这么快,算法还重要吗?"其实永远不会有太快的计算机,因为我们总会想出新的应用.虽然在摩尔定律的作用下,计算机的计算能力每年都在飞快 ...

  4. 基本算法学习(一)之希尔排序(JS)

    参考书: 严蔚敏-数据结构 希尔排序(Shell's Sort) 希尔排序又称"缩小增量排序",归属于插入排序一类,简单来说,和我们的插入排序比,它更快. 奇妙的记忆点: 内排序( ...

  5. 大顶堆删除最大值_算法学习笔记(47): 二叉堆

    堆(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小).当根节点保存堆中最大值时,称为大根堆:反之,则称为小根堆. 二叉堆(Binary Heap)是最简单.常用的堆,是一 ...

  6. Surf算法学习心得(一)——算法原理

    Surf算法学习心得(一)--算法原理 写在前面的话: Surf算法是对Sift算法的一种改进,主要是在算法的执行效率上,比Sift算法来讲运行更快!由于我也是初学者,刚刚才开始研究这个算法,然而网上 ...

  7. 算法学习:后缀自动机

    [前置知识] AC自动机(没有什么关联,但是看懂了会对后缀自动机有不同的理解) [解决问题] 各种子串的问题 [算法学习] 学习后缀自动机的过程中,看到了许多相关性质和证明,但是奈何才疏学浅(lan) ...

  8. 算法学习:后缀数组 height的求取

    [前置知识] 后缀数组 [定义] [LCP]全名最长公共前缀,两个后缀之间的最长前缀,以下我们定义 lcp ( i , j ) 的意义是后缀 i 和 j 的最长前缀 [z函数] 函数z [ i ] 表 ...

  9. 算法学习:最小圆覆盖

    [参考博客] https://www.cnblogs.com/bztMinamoto/p/10698920.html [定义] [圆]一个圆心和他的半径,就能够确定这个半径 [解决问题] 字面意思 给 ...

  10. 算法学习:强连通分量 --tarjan

    [定义] [强连通分量] 在一个子图中,任意点能够直接或者间接到达这个子图中的任意点,这个子图被称为强连通分量 [解决问题] 求图的强连通分量 同时能够起到 ...................缩点 ...

最新文章

  1. Go 语言编程 — 错误处理
  2. Spring Boot Spring MVC异常处理原理分析
  3. 1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains解决
  4. java中json数据_java中的JSON对象的使用
  5. 20175204 张湲祯 2018-2019-2《Java程序设计》第三周学习总结
  6. 首尔2017年公共区域全覆盖免费WiFi
  7. 1061. Dating (20)-PAT甲级真题
  8. 18. Magento 细节
  9. iOS安全攻防(十三):数据擦除
  10. 汉斯·乌尔里希·鲁德尔-唯一一个钻石金双剑金橡叶骑士勋章获得者
  11. [商业_法务] 2、注册公司起名很费劲,用C++怒写个随机名字生成器
  12. 伍德里奇计量经济学第三章课后计算机作业,伍德里奇---计量经济学第7章部分计算机习题详解(STATA)...
  13. 微信小程序01-底部导航栏设置
  14. 中国工业互联网相关政策汇总分析:“十四五”系列规划助力工业互联网创新融合发展[图]
  15. Android8.0 Fingerprint指纹启动流程详细分析
  16. Linux —— 时间问题(localtime和gmtime)
  17. 5大可以赚钱的视频平台,及收益渠道!
  18. 【pytorch EarlyStopping】深度学习之早停法入门·相信我,一篇就够。
  19. enable multi-tenancy on openstack pike
  20. 小白都能看懂的go语言包管理工具DEP详解

热门文章

  1. su 和 sudo -i、su root区别
  2. VB作业之字母大小写的转换
  3. vue+elementui项目中遇到的坑/难题
  4. VS2010操作Excel编程
  5. ddos攻击是什么 怎么防ddos攻击教程
  6. VS1005 VSOS 固件和 MegaLib 亮点
  7. 【Vue】16.vue项目里引入百度统计
  8. SQL Server 2005 安装图解
  9. 2022-2028年全球与中国鸟类保健品行业发展趋势及竞争策略研究
  10. 远程控制安卓终端步骤笔记