算法
叕叕666
这个作者很懒,什么都没留下…
展开
-
有苦有乐的算法 --- 图的宽度优先遍历
题目给定一个图,使用队列对其进行宽度优先遍历代码public static void bfs(Node start) { if (start == null) { return; } Queue<Node> queue = new LinkedList<>(); HashSet<Node> set = new HashSet<>(); queue.add(start); set.add(start); while (!queue.isE原创 2021-12-09 15:08:41 · 140 阅读 · 0 评论 -
有苦有乐的算法 --- 图的深度优先遍历
题目给定一个图,使用栈对其进行深度优先遍历代码public static void dfs(Node node) { if (node == null) { return; } Stack<Node> stack = new Stack<>(); HashSet<Node> set = new HashSet<>(); stack.add(node); set.add(node); System.out.println(node.val原创 2021-12-09 15:06:34 · 182 阅读 · 0 评论 -
有苦有乐的算法 --- 并查集的实现原理
假如有两个集合:找出一个节点作为集合的‘头’,集合内的其他节点都与这个‘头’进行关联(可以直接找到这个‘头’);如果需要在集合A中查找一个元素是否存在,或者判断两个元素是否属于同一集合,只需判断它们的‘头’是否相同即可;当集合B想要加入集合A时,只需让集合B的头关联集合A当在集合A中查找7和8是否属于同一集合时,找到最顶级的‘头’,判断是否相同;找到最顶级的‘头’之后,将经过的节点全部与‘头’关联包括自己;查找7的‘头’后:查找8的‘头’后:...原创 2021-11-29 14:43:06 · 59 阅读 · 0 评论 -
有苦有乐的算法 --- 判断一颗二叉树是否是完全二叉树、是否是平衡二叉树、是否是搜索二叉树
是否是完全二叉树完全二叉树:二叉树的每一层要么是满的,要么从左到右处在变满的路上。public static boolean isCBT(Node head) { if (head == null) { return true; } return process(head).isCBT;}public static class Info { public boolean isFull; public boolean isCBT; public int height; public原创 2021-11-18 15:40:14 · 234 阅读 · 0 评论 -
有苦有乐的算法 --- 获取二叉树的最大宽度
题目一颗二叉树,求其最大宽度。例:解析按层遍历二叉树;在遍历时,使用用4个变量来记录信息;Node curEnd = null; // 当前层,最右节点是谁Node nextEnd = null; // 下一层,最右节点是谁int max = 0; // 暂时最大宽度int curLevelNodes = 0; // 当前层的节点数头结点入队,curEnd = 头结点;nextEnd = 头结点的右节点;头结点出队,curLevelNodes ++,此时 出队节点==curEnd,原创 2021-11-17 17:05:59 · 395 阅读 · 0 评论 -
有苦有乐的算法 --- 二叉树的按层遍历
题目给定一个二叉树,进行按层遍历。例:解析给定一颗二叉树:首先准备一个队列,让头节点入队;节点出队并打印,同时此节点的左节点2入队,右节点3在入队;2出队,2的左节点4入队,2的右节点5在入队;3出队,3的右节点6在入队;最后以此出队,得到结果。代码public static class Node { public int value; public Node left; public Node right; public Node(int v) { value原创 2021-11-17 14:49:04 · 195 阅读 · 0 评论 -
有苦有乐的算法 --- 用栈和递归的方式实现二叉树的前序遍历、中序遍历、后序遍历
前序遍历递归方式:public static void pre(Node head) { if (head == null) { return; } System.out.println(head.value); pre(head.left); pre(head.right);}栈的方式:public static void pre(Node head) { System.out.print("pre-order: "); if (head != null) { Stack原创 2021-11-17 14:17:57 · 260 阅读 · 0 评论 -
有苦有乐的算法 --- 可能有环也可能无环的两个单链表,判断这两个链表是否相交,如果相交返回相交的第一个节点
题目可能有环也可能无环的两个单链表,判断这两个链表是否相交,如果相交返回相交的第一个节点。解析第一步,判断链表是有环链表还是无环链表;如果一个单链表无环,它一定有一个指向null的尾结点;如果一个单链表有环,用两个指针oneStep,twoStep,twoStep一次走两个节点,oneStep一次走一个节点,这两个指针必定会相遇;此时将twoStep重新遍历,一次走一个节点,oneStep也继续一次走一个节点,二次相遇的时候,这个节点就是入环节点。第二步,判断是否相交;2-1:一个单链表有原创 2021-11-15 16:47:56 · 652 阅读 · 0 评论 -
快速排序、归并排序、堆排序的对比,如何选择最优的排序?
快速排序、归并排序、堆排序都是时间复杂度为O(N*logN)的排序,那么该用哪种排序算法呢?快速排序、归并排序、堆排序空间复杂度的对比:快速排序归并排序堆排序O(logN)O(N)O(1)发现,堆排序的堆排序的空间复杂度最低,那么是不是堆排序最好呢?其实还是要看具体场景的。如果即需要追求速度,还需要减少空间的使用,那么堆排序是首选的。快速排序、归并排序、堆排序都是时间复杂度为O(N*logN),但常数时间项快速排序是最低的;如果只需要追求速度,那么快速排序是首选的原创 2021-11-12 14:06:54 · 1420 阅读 · 0 评论 -
有苦有乐的算法 --- 基数排序
题目一个无序数组,使用基数排序的方式从小到大进行排序解析给定一个数组:首先准备一个"桶"(每个桶是一个队列);从左到右遍历数组,每个元素的个位数是多少,就进入几号桶中;在从左到右遍历桶,桶内元素先进先出依次排列,得到了一个按个位数从小到大排序的数组;这个数组从左到右遍历数组,每个元素的十位数是多少,就进入几号桶中,在遍历桶依次排列元素,按十位数从小到大排好序的数组;在按照百位数重复操作,得到了最终排好序的数组;代码public static void radixSort(in原创 2021-11-10 20:13:54 · 545 阅读 · 0 评论 -
有苦有乐的算法 --- 计数排序
题目一个数组,其数据范围在0~200之间,将其从小到大排序解析给定一个数组;首先获取去最大值,然后创建一个长度为这个最大值+1的临时数组;遍历原数组,如果原数组中的元素是n,在临时数组索引为n的位置加1;临时数组为:把元素的索引作为值,元素作为值的个数复制到原数组;代码public static void countSort(int[] arr) { if (arr == null || arr.length < 2) { return; } int max =原创 2021-11-08 11:16:01 · 50 阅读 · 0 评论 -
有苦有乐的算法 --- 一个无序数组,如果从小到大排好序,任何一个元素任何一个元素移动索引长度不超过k,实现排序
题目一个无序数组,如果从小到大排好序,任何一个元素任何一个元素移动索引长度不超过k,实现从小到大排序例:k=2排序后,[4]移动2个索引,[6]移动2个索引,[1]移动2个索引,[3]移动2个索引,[7]移动1个索引,[6]移动1个索引解析给定一个满足条件的数组,k=2;创建一个 大小为k+1的小根堆,先填满,出一个元素,在入一个元素即可实现排序代码public static void sortedArrDistanceLessK(int[] arr, int k) { if (k ==原创 2021-11-02 14:59:44 · 179 阅读 · 0 评论 -
有苦有乐的算法 --- 随机快排
题目使用随机快排对给定数组进行从小到大排序[5,3,2,1,5] ⇒ [1,2,3,5,5]解析给定一个数组1.在数组中找出一个数作为基准(最右侧的数2);变量l记录数组头位置,变量r记录尾位置2.从l位置开始找到大于基准数的位置。l位置元素与基准数比较,3>2,3和r位置数据交换,r减13.从r位置开始找到小于基准数的位置。r位置元素与基准数比较,7>2,r减1;5>2,r减1;1<2,1和l位置数据交换,l加1;4.重复步骤2,l>=r时停止,此时数原创 2021-11-01 15:23:56 · 117 阅读 · 0 评论 -
有苦有乐的算法 --- 小和问题
题目一个无序数组,获取每个元素在左面比这个元素小的个数,求这些个数的和例:[3,2,5,1,4] ==> 6[4,7,0,8,2,4,9,4] ==> 14解析准备一个无序数组,将这个数组平均分成两部分,再把每一部分在平均分成两部分,以此类推,直到分成只剩一个数为止;最右侧的[1,4]先合并,[1]为左部分,[4]为右部分,合并时左部分的1比右部分的4小,小和个数+1;之后[3,2]合并,[3]为左部分,[2]为右部分,合并时左部分的[3]不比右部分的[2]小,小和个数不原创 2021-10-29 17:22:57 · 71 阅读 · 0 评论 -
有苦有乐的算法 --- 归并排序
题目对无序数组进行归并排序,使其有序解析准备一个无序数组,将这个数组平均分成两部分,再把每一部分在平均分成两部分,以此类推,直到分成只剩一个数为止在将每一部分排序后依次返回代码public static void process(int[] arr, int L, int R) { if (L == R) { return; } int mid = L + ((R - L) >> 1); process(arr, L, mid); process(arr, m原创 2021-10-29 16:06:59 · 105 阅读 · 0 评论 -
有苦有乐的算法 --- 自定义一个栈,实现压栈(push)、弹栈(pop)、获取站内最小值(getmin)
题目自己定义一个栈的class,要求此栈有三个方法push、pop、getminpush:往栈中压入一个数据pop:从栈中弹出一个数据gitmin:过去这个栈中最小的数据单不弹出解析准备两个栈stackData、stackMin压栈时,stackData压入数据;stackMin栈顶数据大于需要压入的数据,stackMin也压入这个数据,stackMin栈顶数据小于需要压入的数据,重复压入stackMin栈顶数据。例如需要压入的数据依次是:[4,7,3,5,1]弹栈时,stackD原创 2021-10-29 11:39:43 · 437 阅读 · 0 评论 -
有苦有乐的算法 --- 使用队列结构实现栈结构
题目队列实现栈解析首先准备两个队列queue1、queue2数据[1,2,3,4,5]依次入队queue1,之后把[1,2,3,4]依次出兑在入队到queue2,[5]留在queue1中此时[5]在出队可实现"出栈"操作,[5]出队都queue2中的数据依次返回queue1中,新加的元素此时接在其后即可代码public static class TwoQueueStack<T> { public Queue<T> queue; public Queue<原创 2021-10-28 15:02:10 · 90 阅读 · 0 评论 -
有苦有乐的算法 --- 使用栈结构实现队列结构
题目栈实现队列解析两个栈,stack1,stack2假如一组元素为[1,2,3,4,5],先依次入stack1在将stack1的所有数据出栈,在入stack2注:stack1里的的数据一定要一起出栈;stack2中有数据stack1里的的数据不能出栈stack2出栈即可实现队列操作代码public static class TwoStacksQueue { public Stack<Integer> stackPush; public Stack<Intege原创 2021-10-27 17:40:18 · 63 阅读 · 0 评论 -
有苦有乐的算法 --- 一个数组中,有两种数出现了奇数次,其余数都出现了偶数次,找到这两种数
题目一个数组中,有两种数出现了奇数次,其余数都出现了偶数次,找到这两组数例:[2,4,3,2,5,4] ⇒ [3,5][1,4,6,3,7,8,3,2,1,2,6,6,7,8] ⇒ [6,4]解析异或:0^N=N;N^N=0;(a^b)^c=a^(b^c)假设满足条件的数组:[2,4,3,2,5,4] ;用0去异或数组中每一个数0^2^4^3^2^5^4 = 0^(2^2)^(4^4)^3^5=3^5,可得:一个满足条件的数组,这两个出现了奇数次的数记为a和b;0异或这个数组可以可得到a原创 2021-10-27 16:17:49 · 556 阅读 · 0 评论 -
有苦有乐的算法 --- 一个int类型的数,换成二进制后,提取最右侧的1所在位置
问题一个int类型的数,换成二进制后,提取最右侧的1所在位置3 = 00000011 ==> 00000001 = 14 = 00000100 ==> 00000100 = 4解析如图所示:N&(~N+1)就得到了所需要的数~N+1=-N所N&-N即为结果代码public static int bit1counts(int N) { int rightOne = N & (-N); return rightOne ; }...原创 2021-10-25 17:01:21 · 277 阅读 · 0 评论 -
整数的原码、反码、补码、移码
计算机再存储一个数时是已二进制的方式存储的,并且第一个作为符号位(0代表正数,1代表负数)例:byte temp = 3;3表示为:00000011对于一个正数来说,原码、反码、补码是相同的,移码为补码的符号位取反例:元素:+3原码:00000011反码:00000011补码:00000011移码:10000011对于一个负数来说,原码,反码为原码不带符号位的取反,补码为其反码加1,移码为补码的符号位取反例:元素:-3原码:10000011反码:11111100补码:1原创 2021-10-25 16:39:47 · 3054 阅读 · 5 评论 -
二进制运算之与(&)、或(|)、非(~)、异或(^)
与(&)1&1=1否知为0例:或(|)0|0=0否知为1例:非(~)1变0,0变1例:注:正数取反之后变成了负数的补码,整体再取反后在加负号才是实际值异或(^)0^1=1否知为0例:原创 2021-10-25 16:10:42 · 504 阅读 · 0 评论 -
有苦有乐的算法 --- 在一个数组中,有一种数出现了奇数次,其余数都出现了偶数次,找到这种数
题目在一个数组中,有一种数出现了奇数次,其余数都出现了偶数次,找到这种数例:[1,1,4] ==> 4[1] ==> 1[2,3,6,3,1,2,1] ⇒ 6解析因为N^N=0; N^0=N。所以0^N^N^…^N^N(偶数个N)=0;0^N^N^…^N(奇数个N)=N由于异或是满足交换律的,所以0^M^N^…^M^N(偶数个N,偶数个M)=0;0^M^N^…^M^N^N(奇数个N,偶数个M)=N假设此数组为:[4,4,4,5,5,3,3,7,7,7,7,1,1,1,原创 2021-10-25 15:46:19 · 457 阅读 · 0 评论 -
有苦有乐的算法 --- 两个元素交换的三种方式
方式一public static void swap(int[] arr, int i, int j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j];}缺点:自身异或自身等于0,在部分场景使用可能出现问题方式二public static void swap(int[] arr, int i, int j) { int temp = arr[i];原创 2021-10-20 11:41:00 · 179 阅读 · 0 评论 -
有苦有乐的算法 --- 有序数组中的元素存在问题、最左元素问题和无序数组局部最小问题
一个有序数组,判断是否含有一个元素解析:给定一个数组如果需要判断是否存在的元素为3。首先找到数组的中间元素;如果此元素为3,结束;如果不是,此元素与3比较,此元素如果大于3,在从此元素左边的部分数组寻找中间元素,以此类推。如果查找到最后都不是3,证明3在数组中不存在。代码:public static boolean isExistInArray(int[] sortedArr, int num) {if (sortedArr == null || sortedArr.length原创 2021-10-20 11:21:22 · 144 阅读 · 0 评论