![](https://img-blog.csdnimg.cn/20210726173825380.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
算法题解
刷题的笔记
R_Arisa
这个作者很懒,什么都没留下…
展开
-
力扣19. 删除链表的倒数第 N 个结点
力扣19. 删除链表的倒数第 N 个结点,C++的递归方法原创 2023-02-02 15:36:46 · 96 阅读 · 0 评论 -
力扣24. 两两交换链表中的节点
力扣24. 两两交换链表中的节点原创 2023-02-02 14:59:04 · 317 阅读 · 0 评论 -
力扣844. 比较含退格的字符串
力扣844. 比较含退格的字符串题解原创 2023-01-30 18:58:41 · 157 阅读 · 0 评论 -
剑指Offer 26.树的子结构
题目地址我的思路是判断当前结点是否匹配,若匹配则返回true,否则继续判断它的两个子树。判断匹配的过程是这样的:当前结点值不相等则返回false,否则继续。判断当前结点的两个子树。代码如下:private: bool judge(TreeNode* A, TreeNode* B) { // 不论是isSubStructure还是judge的递归调用都保证了B不会是nullptr // 因此当A为空时一定是不匹配的 if (A == nu原创 2022-04-08 20:37:00 · 169 阅读 · 0 评论 -
剑指Offer 22.链表中倒数第k个节点
题目地址快慢指针将慢指针指向头结点,快指针指向其之后k个节点,使得二者之间距离为k。将它们一起向后移动,直到快指针指向nullptr,此时慢指针就指向倒数第k个结点。ListNode* getKthFromEnd(ListNode* head, int k) { if (head == nullptr) return head; ListNode *fast = head->next; ListNode *slow = h原创 2022-04-08 17:26:03 · 1125 阅读 · 0 评论 -
剑指Offer 07.重建二叉树
重建二叉树题目思路前序遍历的顺序是[(根结点), (左子树前序遍历), (右子树前序遍历)]中序遍历的顺序是[(左子树中序遍历), (根结点), (右子树中序遍历)]采用递归的思想。既然前序遍历是从根结点开始,那么就根据前序遍历数组的第一个结点记为root,在中序遍历中找到root。然后删除前序遍历数组中的根结点。以新的前序遍历数组和中序遍历数组中root左侧部分为输入,构造root的左子树。再以新的前序遍历数组(注意此时前序遍历数组的首结点在上面的递归中删除了一个)和中序遍历数组中root右侧原创 2022-03-30 22:14:46 · 773 阅读 · 0 评论 -
动态连通性问题:union-find算法
问题描述是这样的:输入一列整数对,每个整数对(p,q)表示p和q是相连的,每个点称作触点,每个相连的触点的集合称作连通分量。输出所有不能相连的整数对(即连通分量)的数量通过union-find算法解决该问题。其API如下:方法描述UF(int N)初始化N个触点void union(int p, int q)连接p和qint find(int p)p所在连通分量的标识符boolean connected(int p, int q)如果p和q在同一个连通分原创 2021-09-06 20:25:57 · 120 阅读 · 0 评论 -
算法第四版练习题:热还是冷
题目描述是要猜出1~N之间的一个秘密整数。每次猜测之后,如果相等则游戏结束,否则会得知和上一次猜测相比是更加接近(热)还是远离(冷)。我的思路是利用二分的思想,将秘密数的区间范围从1~N逐渐缩小直到找到。记录下代码:/*热还是冷?随机生成一个1~N的整数:秘密数,猜测它,如果猜对则结束相较于上一次猜测,更接近或不变时为热,否则为冷 */import edu.princeton.cs.algs4.*;import java.lang.Math;class HotColdGame {原创 2021-09-06 16:21:49 · 96 阅读 · 0 评论 -
力扣28.实现strStr
实现strStr题目这道题就是实现一个字符串匹配算法,以前学到过BF和KMP算法,先实现这两个算法。以后有时间学了其他算法再来实现其他的。BF算法最先想到的当然是暴力求解。但是第一次写成的代码相比BF虽然时间复杂度是一样的,但是冗长了不少- -!改进一下就是BF算法:class Solution {public: int strStr(string haystack, string needle) { if (needle == "") return原创 2021-08-19 11:41:55 · 132 阅读 · 0 评论 -
力扣151.翻转字符串里的单词
翻转字符串里的单词题目使用额外空间的方法最先想到的方法是遍历字符串,将最终结果储存到结果字符串中。因为每个单词的顺序都要翻转,所以从字符串的末尾开始向前遍历。由于是逆序遍历,为了保持每个单词不被改变,使用栈存储每个单词的字母,再输出后就可以恢复正常顺序。对于冗余的空格,在遇到时只需将其出栈即可。class Solution {public: string reverseWords(string s) { stack<char> word_stack; //原创 2021-08-16 15:18:05 · 173 阅读 · 0 评论 -
力扣541.反转字符串II
反转字符串II题目这道题有两个思路,迭代和递归。迭代迭代方法从字符串的首位开始,每次操作一个长度为k的区间。如果这个区间的右端超出了边界,那么就反转剩下的所有字符串,否则反转这个区间中的字符串。每次迭代将区间向前移动2k个长度。class Solution {public: string reverseStr(string s, int k) { int length = s.length(); int left, right; char原创 2021-08-14 14:58:32 · 211 阅读 · 0 评论 -
力扣1.两数相加
两数相加题目思路暴力枚举的话时间复杂度是O(n²)O(n²)O(n²),既然大量时间都花费在寻找target - x上,那么就要降低查找的时间。使用unordered_map可以将查找的时间复杂度降到O(1)O(1)O(1),这样的话只需遍历一次数组,时间复杂度就可以降到O(n)O(n)O(n)。代码class Solution {public: vector<int> twoSum(vector<int>& nums, int target) {原创 2021-08-09 12:19:43 · 93 阅读 · 0 评论 -
力扣202.快乐数
快乐数题目思路题目中提示说对于一个正整数,要么最终到达1,要么进入无限循环。也就是说,在求平方和时出现了以前出现过的数字就表示进入了循环,也即该数不是快乐数。那么问题就转化为检查一个数字是否重复出现,我首先想到的就是将出现过的数字都放在集合里,后面每次求和都检验其是否出现过。在题解中看到了解决这种问题的第二种常规思路:快慢指针。由于每次求和的行为都可以看做链表的延伸,那么检查有无重复数字也就是检查链表有没有环,这就无可厚非地要用到快慢指针法了。代码解法一:哈希集合法class Solution原创 2021-08-06 11:00:20 · 117 阅读 · 0 评论 -
力扣1002.查找常用字符
查找常用字符题目思路统计每一个字符串中字母出现的频率,将其最小值记为最终答案的次数。代码class Solution {public: vector<string> commonChars(vector<string>& words) { // 储存每个字符串中相同字母出现的频率的最小值 int minFrequency[26] = {0}; // 先把第一个字符串的频率记录下来 for (int i原创 2021-08-04 12:36:20 · 87 阅读 · 0 评论 -
力扣242.有效的字母异位词
有效的字母异位词题目思路首先两个字符串的长度肯定得相等,否则一定不是字母异位词。然后维护一个长度为26的字母频率数组,用于存储每个字母出现的次数。第一个字符串的字母每次出现频率+1,第二个字符串的字母每次出现频率-1。这样的话,如果最终所有字母的频率都为0,则表示两个字符串的字母出现次数一样多,即是字母异位词。代码class Solution {public: bool isAnagram(string s, string t) { // 数组长度 const原创 2021-08-04 11:37:11 · 78 阅读 · 0 评论 -
力扣206.反转链表
反转链表题目思路思路是把原链表的每个箭头的指向都给反转过来,由于改变指向后就不能访问下一个节点,因此得使用双指针。维护一个指针newhead,指向nullptr。然后从链表的头节点开始遍历,每次把新的头节点设为当前节点的next,这是一个让原链表的箭头逐个反向的过程。就像这样:代码class Solution {public: ListNode* reverseList(ListNode* head) { ListNode* cur = head; Lis原创 2021-08-01 17:55:54 · 113 阅读 · 0 评论 -
力扣977.有序数组的平方
有序数组的平方题目地址思路题目要求时间复杂度要为O(n)O(n)O(n),那就肯定不能用最简单的先赋值再排序的方法。考虑原数组是一个有序的数组,即使平方后也是十分有序的一个数组。不妨假设原数组从负数到正数,就可以将其分为两部分:前面是平方递减的,后面是平方递增的(以0位分界)。在看《算法》时记得说对于有序数组,归并排序是最快速的一种算法。因此这道题就可以考虑使用归并的思路进行解答。使用两个指针分别指向原数组的首位元素和末位元素,这也是原数组平方后最大的两头(依旧不妨设其有负有正)。从最大的两数开原创 2021-07-31 18:53:11 · 97 阅读 · 0 评论 -
力扣707.设计链表
设计链表题目思路就是简单的链表实现,写的时候发现删除可以不用维护pre指针,记录一下代码。代码class MyLinkedList {public: struct Node { int val; Node* next; Node() : val(0), next(nullptr) {} Node(int val, Node* next) : val(val), next(next) {} };原创 2021-07-30 16:05:04 · 66 阅读 · 0 评论 -
力扣66.加一
加一题目思路思路很简单,首先无论如何先给末位+1。如果此时末位不是10,那么可以直接返回,如果末位是10,那就将本位设为0,并向前循环进位。此时有两种情况。一是形如“119”这样的数字,在中间就会停止,遍历到某一位元素加一后不为10即可。另一种情况是形如“999”这样的数字,会遍历到首位元素仍需要进位,此时由于全部数字都已经设为0了,因此只需要在数组最前端插入一个1即可。代码class Solution {public: vector<int> plusOne(vecto原创 2021-07-28 11:18:58 · 63 阅读 · 0 评论 -
力扣11.盛水最多的容器
盛水最多的容器题目思路最开始想到的是暴力求解法,即以每一个元素为一边,计算它与另外n-1个元素分别组成的面积,取其最大值。以第一个元素为一边,遍历n个-1元素。然后以第二个元素为一边,遍历n-2个元素。以此类推,是以等差递减的次数遍历(1 + n) * n / 2次,时间复杂度是O(n2)O(n^2)O(n2)。这个答案会超时,因此得想想更快的方法。假设两个边的下标分别是left和right,他们围成的面积就应该是它们之间的距离乘二者中更短的那个,即:(right−left)∗min(heig原创 2021-07-27 12:24:46 · 103 阅读 · 0 评论 -
力扣26.删除有序数组中的重复项
删除有序数组中的重复项题目思路使用双指针法,用快指针找到下一个不相同的元素,用慢指针维护结果数组。整个过程就是用快指针遍历一次数组,一次时间复杂度是O(n)O(n)O(n)。代码class Solution {public: int removeDuplicates(vector<int>& nums) { if (nums.size() == 0) return 0; int i = 0, j = 1;原创 2021-07-27 10:48:25 · 192 阅读 · 0 评论 -
力扣59.螺旋矩阵Ⅱ
螺旋矩阵Ⅱ题目思路由外向内螺旋的时候都只操作最外圈的元素,因此可以每次循环处理一圈元素,然后把边界缩小,直到边界越界(即左边界在右边界的右边)代码class Solution {public: int num = 1; vector<vector<int>> generateMatrix(int n) { vector<vector<int>> matrix(n, vector<int>(n)); // 每次绕圈时原创 2021-07-26 21:54:34 · 123 阅读 · 0 评论 -
力扣2.两数相加
两数相加题目思路同时遍历两个链表,直到两个都为nullptr。如果中途一个链表指针为空,则将其数字设置为0。两数相加时维护一个进位变量carry,若相加之和≥10,则将carry设为1,否则为0。每次加法操作都由两数和carry共同相加。p.s.虽然不喜欢数电课,但是进位变量确实是受加法器的启发。代码// 注意:不是最终正确版本class Solution {public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {原创 2021-07-26 17:35:47 · 85 阅读 · 0 评论 -
力扣209.长度最小的子数组
题目地址思路使用滑动窗口的方法,利用双指针进行遍历。首先是窗口的右端递增,直到元素和满足条件,或者碰到边界。然后是窗口左端收缩,每次收缩都更新更小的子数组长度。如此循环右端和左端交替递增以遍历数组。由于每个元素最多只有进、出窗口两个行为,即最多被操作两次,因此时间复杂度是O(n)O(n)O(n)。代码class Solution {public: int minSubArrayLen(int target, vector<int>& nums) {原创 2021-07-26 11:28:35 · 88 阅读 · 0 评论 -
力扣27.移除元素
移除元素题目地址思路既然不能使用额外的空间,那就不能重新创建一个数组。题目说元素的顺序可以改变,因此可以换一个思路:不去真正的删除元素,而是给这个位置换一个值。既然最后返回的是新数组的长度,那么尾部的元素就是被抛弃的元素,因此可以把要删除的元素和尾部的元素交换。代码class Solution {public: int removeElement(vector<int>& nums, int val) { int j = nums.size() - 1原创 2021-07-25 11:31:59 · 135 阅读 · 0 评论