
算法刷题
面试与笔试中遇到的一些题,以及一些数据结构算法方面的总结。
罗古洞的女婿
保持热情
展开
-
笔试题------查找积分对
有关整除,倍数等问题可以试试转化成余数来做。这是一道华为的笔试题。本答案仅供参考。#include<bits/stdc++.h>using namespace std;// 计算余数数组,如果配对能成,则两数余数相加一定等于average或0int main(){ int average, N; // 历史平均得分和人数 cin>>average>>N; N = N * 2; // cout<&l..原创 2021-09-15 22:47:35 · 474 阅读 · 1 评论 -
leetcode15. 三数之和
class Solution {public: vector<vector<int>> threeSum(vector<int>& nums) { int len = nums.size(); vector<vector<int>> ans; // 数组长度小于3就不用算三数之和了 if(len < 3) return ans; ...原创 2021-08-09 13:16:00 · 87 阅读 · 0 评论 -
leetcode322 & 518. 零钱兑换
经典动态规划:考虑最后一步,如果要凑成金额i,最后一步用的是硬币c,那么总共的硬币数就是 dp[i - c] + 1dp[i]是状态数组,含义是凑成金额i最少需要多少硬币。转移方程:dp[i] = dp[i - c] + 1class Solution {public: int coinChange(vector<int>& coins, int amount) { int len = coins.size(); vect...原创 2021-08-09 10:32:55 · 136 阅读 · 0 评论 -
leetcode572. 另一棵树的子树
主要分两种情况,一种是两棵树有相同的根节点,一种是子树在原树的左子树或者右子树上。/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(i...原创 2021-08-09 09:44:27 · 236 阅读 · 0 评论 -
剑指offer 07. 重建二叉树
https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/二叉树的问题一般都是用递归。这里给出了前序遍历序列和中序遍历序列,要求重建二叉树。我们用一个递归函数func来实现这个功能,func函数六个参数:preorder:前序数组inorder:中序数组pre_left:递归时候用于切分前序数组的左边界pre_right:递归时候用于切分前序数组的右边界in_left:递归时候用于切分中序数组的左边界in_ri原创 2021-08-08 17:15:33 · 149 阅读 · 0 评论 -
二叉树的层序遍历问题
https://leetcode-cn.com/problems/maximum-width-of-binary-tree/因为二叉树的结构与满二叉树相同,因此可以用满二叉树的编号方式给二叉树中所有结点编号,当然要通过二叉树的层序遍历来实现。如果一个结点编号为i,那么其左孩子编号就是 2 * i,其右孩子就编号成2 * i + 1。比较重要的是为了防止编号越来越大而超过int的表示范围,可以在给每一层编号的时候减去一个统一的偏移量offset需要在for循环外边定义。/** * Defini原创 2021-08-07 19:44:12 · 141 阅读 · 0 评论 -
leetcode300. 最长递增子序列
动态规划状态数组dp[i]:含义是以nums[i]为结尾的最长递增子序列,这里的意思是这个子序列一定包含nums[i]。状态转移方程:对于所有小于i的索引j,如果nums[j]是小于nums[i]的,那么就可以把nums[i]接上去,形成更长的自增子序列。if(nums[j] < nums[i]){dp[i] = max(dp[i], dp[j] + 1)}class Solution {public: int lengthOfLIS(vector<int&...原创 2021-08-07 18:39:13 · 96 阅读 · 0 评论 -
leetcode76. 最小覆盖子串
https://leetcode-cn.com/problems/minimum-window-substring/滑动窗口法,用left和right来维护一个滑动窗口。用两个哈希表分别用来存储窗口内的字符以及给定的子串。比较巧妙的地方是用cnt来统计滑窗内有多少个有效字符。tips:写代码的时候老是把right和left当成哈希表的键来用,这种小错误需要谨慎。class Solution {public: string minWindow(string s, string.原创 2021-08-07 18:22:55 · 99 阅读 · 0 评论 -
leetcode2. 两数相加
两点考虑,第一点,两个链表长度可能不等,第二点,加完以后可能还有最后一个进位。此外,题中构建链表的方法可以,先定义head和tail都指向nullptr,然后第一个插入结点时让head和tail同时指向第一个结点,接下来用tail来滑动增加结点。构造链表的时候一定得用两个指针才行。/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ...原创 2021-08-07 11:25:31 · 112 阅读 · 0 评论 -
leetcode337. 打家劫舍Ⅲ
两个状态数组,且对于树的问题跟数组不一样,状态数组用的是哈希表,键是树结点的指针,值是以这个结点为根节点的树可以偷到的钱的最高金额。两个状态数组,分别表示今晚偷了根节点和没有偷根节点,y表示偷了根节点的情况下偷的最高金额,n表示没有偷根节点的情况下偷到的最高金额。 当今晚偷了根节点,那么肯定没有偷其两个孩子。即: y[root] = g[root->left] + g[root->right] 当今晚没有偷根节点,那么可以偷其两个孩子,也...原创 2021-08-06 17:09:05 · 141 阅读 · 0 评论 -
leetcode213. 打家劫舍Ⅱ
https://leetcode-cn.com/problems/house-robber-ii/submissions/跟打家劫舍第一题相比就是把房子变成了环状。也就是第一个房子和最后一个房子不能一起偷了。因此可以把偷第1个到第n个房子的问题转换成两个分支,一个是计算偷盗第1个到第n-1个房子,一个是偷第2个到第n个房子。最后看这两个分支哪个钱多,就输出哪一个。注意这里还是用滚动数组来实现的动态规划,降低空间复杂度。class Solution {public: int rob(.原创 2021-08-06 12:13:52 · 146 阅读 · 0 评论 -
leetcode 198. 打家劫舍
https://leetcode-cn.com/problems/house-robber/状态数组 dp[i]意思是从第0个房屋到第i个房屋能偷到的最高金额。考虑偷盗的最后一步,即偷第i个房子的时候,如果偷了i那么就不偷i-1,那么此时偷到的金额是 dp[i] = dp[i - 2] + nums[i]如果没有偷i,那么dp[i] = dp[i - 1]所以状态转移方程为 dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])初始值为 dp[0.原创 2021-08-06 10:53:10 · 110 阅读 · 0 评论 -
两数之和变种------找到所有满足条件的数对
一、数对不重复https://www.lintcode.com/problem/587/description方法是排序加双指针,注意在判断两数之和等于target的分支里边,需要进行去重操作。且while中条件一定要用 i < j,因为中间会改变i和j,用 i != j是不准确的。class Solution {public: /** * @param nums: an array of integer * @param target: An inte原创 2021-08-05 16:33:19 · 626 阅读 · 0 评论 -
leetcode 1605. 给定行和列的和求可行矩阵
https://leetcode-cn.com/problems/find-valid-matrix-given-row-and-column-sums/贪心策略,因为要找到一个可行的非负整数矩阵,我们考虑前边能放元素的时候尽量放上,后边不能放的时候就放0就行。因此矩阵每个位置我们都放上其对应行数组和列数组中的较小值,然后更新行数组和列数组,因为用的是较小值,所以更新以后一定是一个等于0一个大于0。class Solution {public: vector<vector<原创 2021-08-05 10:45:42 · 379 阅读 · 0 评论 -
leetcode 413. 等差数列划分
https://leetcode-cn.com/problems/arithmetic-slices/动态规划,dp[i]的含义是以nums[i]结尾的等差数列的个数则假设nums.size() == 6的话,那么所有的等差字数个数就等于以nums[2] nums[3] nums[4] nums[5]为结尾的等差子数列的个数求和。比如 nums = [1, 2, 3, 4, 5, 6]则以nums[2] = 3结尾的等差数列个数dp[2] = 1,即 1 2 3以nums[3] =.原创 2021-08-05 10:32:10 · 160 阅读 · 0 评论 -
leetcode 64. 矩阵最小路径和
https://leetcode-cn.com/problems/minimum-path-sum/经典二维dp,但是注意二维dp数组要注意边界问题,即在边上的位置和其它位置处理方法可能不一样,递推公式不一样。class Solution {public: int minPathSum(vector<vector<int>>& grid) { // 二维dp,状态函数的含义是到某个位置上的数字总和最少为多少 if(gr.原创 2021-08-04 23:17:48 · 149 阅读 · 0 评论 -
leetcode 257. 二叉树的所有路径
https://leetcode-cn.com/problems/binary-tree-paths/只需要从根节点开始深搜,然后如果遇到一个点既没有左孩子也没有有孩子,那就找到了一条路径。深搜的过程中要用一个字符串记录路径。注意temp不能用引用类型的参数,因为深搜的时候搜到某个路径再回溯的时候temp也应该回退到以前的状态,如果temp是引用类型的话,会导致搜索路径回溯以后temp改变了。即分支污染问题。/** * Definition for a binary tree node.原创 2021-08-04 22:46:38 · 96 阅读 · 0 评论 -
leetcode56. 合并区间
https://leetcode-cn.com/problems/merge-intervals/主要在于两个循环,内循环用于合并小区间,外循环决定了合并之后剩下多少个区间class Solution {public: vector<vector<int>> merge(vector<vector<int>>& intervals) { sort(intervals.begin(), intervals.原创 2021-08-02 23:50:22 · 121 阅读 · 0 评论 -
leetcode 124. 二叉树的最大路径和
https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/最主要是dfs深度优先遍历函数的构造,这里dfs的功能是返回以root为根节点的单边最大路径和,什么叫单边最长路径和呢?就是根节点root的值加上 max(root的左子树上的最大路径和,root的右子树上的最大路径和),把dfs递归函数的功能搞懂了,此题迎刃而解。/** * Definition for a binary tree node. * struct Tr原创 2021-08-02 23:25:23 · 124 阅读 · 0 评论 -
数组中和为k的所有索引对
默认数组中没有重复元素#include <bits/stdc++.h>using namespace std;vector<pair<int, int>> twoSum(vector<int>& nums, int target) { unordered_map<int, int> mp; vector<pair<int, int>> ans; int l原创 2021-08-02 22:55:45 · 114 阅读 · 0 评论 -
三个数组中的三数之和求索引组合总数
题目给定三个数组A,B,C,数组无序,且数组中元素都是正整数。求 A[i] + B[j] + C[k] = w的(i , j, k )的组合总数。要求时间O(N), 空间O(1)。思路对于每个数组建立一个桶(哈希map),每个数组中大于w的数直接忽略,其它数放入桶中,map的第一个元素是数值,第二个元素是频次,即该数值出现的次数。因此三个桶的大小都不大于64,所以占用空间与N无关,空间复杂度O(1),接下来直接遍历统计有多少种相加等于w的组合,方式是让每个数对应的频次相乘即可。由于桶的大小是固定原创 2021-07-28 10:25:52 · 542 阅读 · 0 评论 -
前缀和------解决子数组求和问题
前缀和概念对于一个序列,其前缀和是一个数组,其长度等于序列的长度。前缀和数组中每个元素sum[i]都是原数组arr中前i个元素的和。比如:arr: 0 1 2 3 4 5sum:0 1 3 6 10 15通过两层循环,让sum[i] - sum[j] 就可以得到原数组中所有子数组内元素的和。注意对于从开头开始的子数组直接用sum[i]就能搞定,根本不需要减。接下来看几个例子例子1:leetcode 560 和为k的子数组https://leetcode-cn.com/probl.原创 2021-07-23 13:31:38 · 1041 阅读 · 0 评论 -
剑指offer 48. 最长不重复子串
https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/双指针滑动窗口,首先初始化left和right都在开头,然后固定left不动,让right不断后移,每后移一步,就判断当前字符是否跟窗口内字符重复,如果有重复,则先固定right不动,然后left不断后移,left后移的过程中窗口内的字符不断减少,直到减少到right处的字符在窗口内已不重复,然后继续固定left让right.原创 2021-07-23 10:56:42 · 99 阅读 · 0 评论 -
剑指offer 29. 顺时针打印矩阵
class Solution {public: vector<int> spiralOrder(vector<vector<int>>& matrix) { vector<int> res; if(matrix.size() == 0) return res; /* 依次循环四个动作: 1. 从左到右 2. 从上到下 3. ...原创 2021-07-23 00:06:47 · 87 阅读 · 0 评论 -
剑指offer 03. 数组中重复的数字
1 数字范围长度与数组长度相同最简单的解法就是遍历数组并用一个哈希表存起来,当再次遍历到同一个数字的时候就找到了重复的元素。class Solution {public: int findRepeatNumber(vector<int>& nums) { unordered_set<int> s; for(auto &n : nums){ if(s.find(n) != s.end())原创 2021-07-05 14:17:52 · 112 阅读 · 0 评论 -
基础排序算法------内部排序
1 基础概念排序问题,就是将无序序列排成一个有序序列(升序或降序)。2 插入排序基本思想即边插入边排序,每步将一个待排序的对象,按其关键码大小,插入到前边已经排好序的一组对象的适当位置上,直到全部对象全部插入为止,插入过程中始终保持当前子序列有序。虽说是边插入边排序,貌似一边输入一遍插入排序,像打牌一样,但通常情况下我们都是拿到一个待排序的无序序列,然后进行排序后输出有序序列。即真实过程并不是我们一遍输入一遍排序,而是给定一个无需序列a:在插入a[i]前,数组a的前半段(a[0]原创 2021-07-03 23:02:07 · 1064 阅读 · 1 评论 -
基础查找算法
1 基础概念查找表查找表是同一类型的数据元素构成的集合。如下每个学生的信息记录合在一起构成了查找表。查找就是根据给定的某个值,在查找表中确定也给其关键字等于给定值的数据元素。关键字:用来标识某个数据元素的某个数据项的值。比如给定姓名叫陈红,查找确定查找表中姓名这个数据项的值为陈红的数据元素。主关键字:可以唯一标识一个记录的关键字。比如上表中准考证号。查找表分类静态查找表仅作查询(检索)操作的查找表。动态查找表作插入和删除操作的查找表。有时候在查找的时候需要原创 2021-06-30 22:32:01 · 1490 阅读 · 0 评论 -
leetcode 414 第三大的数
遍历数组,维护三个变量记录最大的三个数,如果遇到相同的数直接跳过,遇到不同的数就跟当前记录的三个最大数比较大小。class Solution {public: int thirdMax(vector<int>& nums) { long long m1 = -9e9, m2 = m1, m3 = m1; for(auto n : nums){ if(n == m1 || n == m2 || n == m3...原创 2021-06-22 15:24:17 · 86 阅读 · 0 评论 -
leetcode 20 有效的括号
用栈解决,遍历字符串,如果碰到左括号,就入栈,如果碰到右括号,就判断栈顶元素是否是其对应的左括号,如果是,就将对应左括号出栈,否则就返回false。字符串遍历完成,如果栈为空,则是有效的括号,否则不是。class Solution {public: bool isValid(string s) { // 括号字符一定成对出现,且左括号先出现 int len = s.length(); if(len % 2 ==1) return fal..原创 2021-06-22 12:30:18 · 72 阅读 · 0 评论 -
leetcode 859 亲密字符串
问题描述问题分析首先亲密字符串长度一定相等是否是亲密字符串,可以分成两种情况一种是两个字符串完全相同,这个时候只要字符串中有重复字符,只要将这两个重复字符位置互换就行了。比如 A = "abacd" = B,只要把两个a换一下位置就行另一种情况是两个字符串有且只有两个位置字符不同,其来他们位置上的字符是反过来的。比如示例1中所示。class Solution {public: bool buddyStrings(string s, string goal) { .原创 2021-06-22 11:57:31 · 151 阅读 · 0 评论 -
栈实现队列与队列实现栈
栈实现队列用栈来模拟队列,实现出队,入队,返回队首元素,查看队列是否为空等功能思路:用两个栈,一个栈s1用来保存所有入队元素,即mei原创 2021-06-19 01:09:23 · 240 阅读 · 0 评论 -
leetcode 142 有环链表的入口
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public: ListNode *detectCycle(ListNode *head) { if(head ==...原创 2021-06-18 22:18:52 · 115 阅读 · 0 评论 -
连续子数组的最大和
class Solution {public: int maxSubArray(vector<int>& nums) { int len = nums.size(), son_sum = nums[0], ans = son_sum; for(int i = 1; i < len; ++i){ if(son_sum < 0){ son_sum = nums[i...原创 2021-06-18 21:34:49 · 112 阅读 · 0 评论 -
二叉树的遍历
前序遍历递归解法这个没啥好说的,前序就是在调用递归函数访问左子树和右子树之前访问当前结点,注意点就是如果前序遍历序列要用数组存储的话,数组一定要定义za迭代解法原创 2021-06-07 20:55:11 · 225 阅读 · 0 评论 -
C++翻转链表
1 题目描述2原创 2021-06-05 23:32:29 · 1245 阅读 · 3 评论 -
马拉车算法manacher
manacher算法1. 预处理解决奇回文和偶回文问题比如 str = "bcbaa",在每个字符的开头,结尾和中间插入一个特殊字符“#”来得到一个新的字符串“#b#c#b#a#a#”, 这样对于原来字符串中的奇回文“bcb”来说,在新的字符串中变成了“#b#c#b#”,还是奇回文,只是回文串长度从3变成了7;注意代码中( i & 1) == 0,与1按位与,如果i是偶数则结果为0,否则为1,因为偶数的二进制表示为 *******0,最后一位为0,而1的二进制表示为0000000原创 2021-03-01 13:40:07 · 168 阅读 · 0 评论