3.9k 词
前言这几天学习了数组的一些小技巧,包括前缀和与差分数组,那么下面我将对其展示自己的理解,并实际应用到一些问题中去。 技巧前缀和数组前缀和数组是一个基于原数组所生成的新的数组,它的第一个元素是0,后面的第i个元素是原数组区间[0,i-1]的和。 首先先说一下实际应用,例题: 【leetcode 303:区域和检索 - 数组不可变】 给定了一个确定的数组,和n个区间,题目要求求出每个区间内的和。 正常思路使用暴力for循环去做,但是时间复杂度较高,并且题目中的sumRange方法最多可以被调用10^4次,那么效率就非常低了,有没有一种方法能够降低时间复杂度呢?没错,就是使用我们刚刚提到的前缀和数组。 对于一个数组,我要求出其区间[i,j]的和,本质相当于计算前缀和数组的第j+1个元素和第i个元素的差,为什么呢,我们慢慢来分析,我们命名前缀和数组为preSum。 1.preSum[j+1]代表原数组区间[0,j]的和。2.preSum[i]代表原数组区间[0,i-1]的和。3.那么preSum[j+1]-preSum[i]就相当于原数组区间[i,j]的和了。 如此,我们思路已经非常清晰...
3.1k 词
前言最近学习了动态规划和回溯,发现他们的本质其实都是对二/多叉树的遍历而已,而动态规划一般再后序位置拿到子问题的解合并为大问题的解,而回溯是再前序添加路径,后序删除路径。 介绍这次我来好好总结一些回溯算法,我认为回溯就是一种暴力穷举法,进行不同的选择时,每个选择还可以进行各种选择,回溯算法本质是在遍历树枝,应用回溯算法来解决问题其实就是在遍历一颗决策树,树的节点上放置着正确答案,你只需要拿到这些答案,问题就解决了。 对于一颗决策树,有三个重要的问题: 路径(track): 遍历经过的节点,其实就是做出的选择 选择列表(candidates): 可以做的选择,在每个节点上都可以进行 结束条件(base case): 到达回溯树的底部,无法继续做出选择 回溯算法框架: public class BacktrackingAlgorithm { public static void main(String[] args) { // 调用回溯函数 backtrack(0); } publ...
4.9k 词
前言最近看了labuladong的算法笔记,感觉对数据结构有有了一写新的理解,这里把链接放出来了 labuladong的算法笔记 这篇文章旨在回顾我在看他笔记时所产生的一些想法,进行复盘,以加深我自己的记忆。 双指针介绍首先, 双指针分为左右指针和快慢指针,而左右指针又分为左右向中间逼近和在中间向两侧逼近,那么接下来我们分别对这些指针开始介绍。 左右指针左右指针通常应用在数组中,为什么链表中应用少,应为链表是单向的话,是无法访问其前面节点的,需要靠额外的空间储存,即使是双向链表,我们也不知道其链表的长度是多少,必须进行一次遍历才能知道,所以在链表中不推荐左右指针。 两侧向中间移动1.二分查找int binarySearch(int[] nums, int target){ int left = 0, right = nums.length -1; while(left < right) { int mid = (left + right) /2; if(target > nums[mid]) {...
636 词
前言一天我在学习JavaSE的时候,学到了PriorityQueue优先级队列这个东西,讲师说道 它这个将元素入队后会自动排序,出队的时候就会按大小排序。 然后我就试了一下,还真是,但是用迭代器打印其中的元素呢,发现事情并不简单… 问题Queue<Integer> queue = new PriorityQueue<>(); queue.offer(10); queue.offer(1); queue.offer(5); queue.offer(2); System.out.println(queue); 可以猜一下,结果是什么,正常按理来说应该顺序是: // [10, 1, 5, 2] 但是实际的顺序是 // [1, 2, 5, 10] 我一直对这个很迷惑,直到我在一个学算法的网站上学到了一个叫堆的东西 8.1 堆 https://www.hello-algo.com/chapter_heap/heap/#813 分析// 10入队 10 / \ //...