Data structures and algorithms
文章平均质量分 58
面试和工作中常用的数据结构和算法的总结以及leetcode中部分面试题的代码实现和算法思路解析
NK_test
大部分人愿意做任何事来逃避真正的思考
展开
-
2016小米在线编程题解
题目一世界上有10种人,一种懂二进制,一种不懂。那么你知道两个int32整数m和n的二进制表达,有多少个位(bit)不同么?思路:很简单啊,异或操作,然后右移算出1的个数。class Solution {public: /** * 获得两个整形二进制表达位数不同的数量 * * @param m 整数m * @param n 整数n *原创 2016-10-21 12:57:13 · 2219 阅读 · 0 评论 -
[leetcode] 162 Find Peak Element(二分)
这题要求我们在一个无序的数组里找到一个peak元素,所谓peak,就是值比两边邻居大就可以了。对于这道题目,最简单的解法就是遍历数组,只要找到第一个符合要求的元素就可以了,时间复杂度为O(n),但是这题要求O(LogN)的时间复杂度,还可以用二分来做。首先我们找到中间节点mid,如果大于两边返回当前的index就可以了,如果左边的节点比mid大,那么我们可以继续在左半区间查找,这里面一原创 2015-11-19 13:09:46 · 4521 阅读 · 0 评论 -
[leetcode] 134 Sort List (链表 & 归并排序)
首先看到题目中要求时间复杂度 O(n log n),时间复杂度为常数的时候,先将最容易实现的插入排序排除(O(n^2));接着想到快速排序和归并排序,但是快速排序的最坏时间复杂度也为O(n^2),想了一会并且感觉也不是很好实现的样子。最后瞅了一眼discuss的代码,发现用的是归并排序,理论上归并排序的空间复杂度是线性的,也就是O(N),并不是常数,这点就需要结合链表的特性,只需要修改指针之间原创 2015-11-17 22:55:07 · 1445 阅读 · 0 评论 -
[leetcode] 219 Contains Duplicate II(map)
思路一:使用map映射 记录出现过的nums[i],并记录对应的位置i ;当出现冲突时,比较两者位置关系,如果之差小于等于k,则返回true,否则更改为新位置;如果没有冲突,则说明不含有重复元素。class Solution{public: bool containsNearbyDuplicate(vector &nums, int k) { map mp;原创 2015-11-08 21:35:22 · 1177 阅读 · 0 评论 -
[leetcode] 16 3Sum Closest(数组)
暴力循环的时间复杂度是O(N^3),肯定是不可取的。我们要充分利用题目中的条件进行分析,如何才能相对高效的比较数组中指定个数元素的和 和target的大小呢?我们可以先对数组进行排序,如果是计算两个元素的和的话,我们会分别设置头和尾两个指针,向中间靠拢,那么三个的话,我们只需要先对第一个数进行循环取值下标i,剩下的两个指针分别指向i+1和数组的最后一个元素,这样的复杂度是 排序O(nlogn原创 2015-11-08 20:25:24 · 2412 阅读 · 0 评论 -
[leetcode] 43 Multiply Strings(模拟大数乘法)
很简单的题目,模拟大数乘法。思路: 第一个字符串的第i位乘以第二个字符串的第j位一定是结果的第i+j位,如果i+j已经有值,直接加上去就OK,并用temp保存进位,最后记得将结果反转,去掉前置0。这样的算法的复杂度是O(n2).利用FFT可以将算法优化到O(nlogn),关于FFT的实现在此不再赘述,可以参考算法导论或者网上其他资料。另外,我的博客中实现原创 2015-11-03 22:24:30 · 4817 阅读 · 0 评论 -
[leetcode] 80 Remove Duplicates from Sorted Array II(数组下标操作)
因为这道题目的题意是要求我们在原数组上进行操作,所以操作变得稍微复杂了些,否则直接使用map最为简单。基本思想是记录两个指针,一个是当前数组,另一个是目的数组,注意如果发现重复数超过2,那么目的数组的cur就要阻塞,直到不同的出现后再赋值前进。class Solution {public: int removeDuplicates(vector& nums) { i原创 2015-10-30 22:39:22 · 4505 阅读 · 4 评论 -
[leetcode] 120 Triangle
感觉acm做过之后,这种题太基本了....没啥好说的,最简单的动态规划,找出状态转移方程就可以了。采用由下到上的思想(这样最后只需要取出dp[0][0]就是答案),本层每个结点的结果根据下面一行的路基累计和而计算,要么取左边的,要么取右边的,两者取最小的即可。状态转移方程:triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1]原创 2015-10-27 23:40:09 · 4598 阅读 · 0 评论 -
[LeetCode]268 Missing Number
很简单,提供两种解法。(1)等差数列先求得总和,然后减去给定的队列,剩下的值就是缺失值。(2)先排个序,逐个比较,不等的直接return第一种的代码:class Solution {public: int missingNumber(vector& nums) { int n = nums.size(); int expect = (n+1原创 2015-10-25 00:16:48 · 3451 阅读 · 0 评论 -
[leetcode] 279 Perfect Squares(DP,四平方和定理)
1. 四平方和定理定理表明 每个正整数均可表示为4个整数的平方和。也就是说这个题的答案,我们可以先在数组中预处理出平方和,然后两层for循环暴力循环判断1,2,顺便可以由剩下的检验一下是不是3,都不是的话,就是4.2. 还是利用四平方和定理,但是用到了很多技巧,这个解法是参考网上的答案:根据四平方和定理,任意一个正整数均可表示为4个整数的平方和,其实是可以表示为4个以内的平方数之和,那原创 2015-10-24 21:31:57 · 3822 阅读 · 0 评论 -
[leetcode] 200 Number of Islands(DFS)
非常基础的一道DFS深度优先搜索的题目,当我们遍历数组发现一个位置为'1'时,就是用dfs将其周围的1全部变为0,然后递归继续,这样所有连通成一片的'1'就是一个island,sum++,最后返回sum即可。类似的题目还有 hdu 1016,hdu 1241。int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};class Solution {public:原创 2015-10-12 23:12:46 · 2889 阅读 · 0 评论 -
[leetcode] 24 Swap Nodes in Pairs(交换链表相邻结点)
(一)迭代法在处理这种问题时,我们通常加上一个dummy头结点指向head,至于思路很清晰了就是隔一个去交换两个相邻结点,比如1->2->3->4->NULL,我们先通过指针交换1和2,再交换3和4,详细的指针操作可以看下面的图:class Solution {public: ListNode* swapPairs(ListNode* head) { Lis原创 2015-10-05 14:03:17 · 2407 阅读 · 0 评论 -
[leetcode] 221 Maximal Square(最大全1正方形 &动态规划)
当我们判断以某个点为正方形右下角时最大的正方形时,那它的上方,左方和左上方三个点也一定是某个正方形的右下角,否则该点为右下角的正方形最大就是它自己了。这是定性的判断,那具体的最大正方形边长呢?我们知道,该点为右下角的正方形的最大边长,最多比它的上方,左方和左上方为右下角的正方形的边长多1,最好的情况是是它的上方,左方和左上方为右下角的正方形的大小都一样的,这样加上该点就可以构成一个更大的正方形。原创 2015-10-04 23:04:17 · 7553 阅读 · 5 评论 -
[leetcode] 22 Generate Parentheses(递归)
简单的递归构造。小括号串是一个递归结构,跟单链表、二叉树等递归结构一样,首先想到用递归。一步步构造字符串。当左括号出现次数小于指定的n时,可以放置新的左括号。当右括号出现次数小于左括号出现次数时,就可以放置新的右括号。我们可以将string放进参数,这样回溯的时候不必在进行删除处理。class Solution { public: void solve(int n,string s,原创 2015-10-01 23:20:57 · 3236 阅读 · 0 评论 -
[leetcode] 134 Gas Station(经典dp || 贪心)
(一)最容易想到的是O(n2)的解法预处理出gas[i] - cost[i] 的数组,从每个非负的位置开始尝试,只要能够完成一个循环,就可以输出结果;对于返回-1的情况,我们经过思考和推论可以得出:对于一个循环数组,如果这个数组整体和 SUM >= 0,那么必然可以在数组中找到这么一个元素:从这个数组元素出发,绕数组一圈,能保证累加和一直是出于非负状态。所以只需要比较sum和0的大小就原创 2015-09-28 14:31:51 · 2964 阅读 · 0 评论 -
[leetcode] 136 &137 Single Number Ⅰ Ⅱ
136;题意很简单,给你一个数组(int),只有一个数字是出现一次的,其余出现两次,不允许使用额外空间,时间复杂度线性。如果允许使用额外空间的话,可以使用map记录次数,最后遍历,也是O(n)的复杂度;但是现在需要把额外空间也去掉,我们只能向位操作方面想了。利用异或的特点,可以发现 (1) a^a =0(2) 0^ b=b所以,相同的两个数异或结果肯定是0,而0与唯一的出现原创 2015-09-25 00:00:09 · 1738 阅读 · 0 评论 -
[leetcode] 152 Maximum Product Subarray
先来一个比较简单的题目,也是出现较多的,求连续的最大子数组和,见hdu 1003.比较简单的动态规划,如果当前的连续和小于0时,再加则一定会小于nums[i]的当前值,此时应该取nums[i].#include#includeusing namespace std;int a[100001];int sum[100001];int main(){ int n;原创 2015-09-22 23:54:39 · 3939 阅读 · 0 评论 -
[Leetcode] 11 Container With Most Water
首先,刚看到这道题的时候,我是往动态规划方向去想的,后来构造不出转移方程。所以再次进行思考,想按照三种方式取最大值即:1)right左移一位2)Left右移一位3)Right左移一位,left右移一位三者取最大值,但是不能证明局部最优可以带来全局最优,而且找到了反例。我们试想如果为了局部最优而导致左右均接近一位的话,有可能错过一个最大高度。那么我们如何才能不错过最大高度呢?只需原创 2015-09-18 15:22:35 · 1605 阅读 · 0 评论 -
[leetcode] 139 Word Break
这题可以用DFS做,但是更好的方法是使用DP,这种类型的DP感觉还是接触的稍微有些少。题目中只要求源串分出来的词只要都在字典里就好,所以我们可以用dp[i] 表示源串的前i个字符可以满足分割,那么 dp[ j ] 满足分割的条件是存在k (0class Solution {public: bool wordBreak(string s, unordered_set& word原创 2015-09-13 23:32:19 · 2270 阅读 · 0 评论 -
[leetcode] 179 Largest Number
拿到这个题的第一个想法是 将int转换成string,然后按照string的比较规则,但是发现 13那么何不我们直接比较下两者的组合,取其较大的呢,由此自定义优先级比较即可。注意处理全是0的情况,只输出一个0即可。class Solution {public: static bool comp(string s1,string s2) { retur原创 2015-09-12 12:24:02 · 2098 阅读 · 0 评论 -
[leetcode] 187 Repeated DNA Sequences
(一)最一开始的做法是使用 map 记录每个10个字符的字符串的个数,超过2就push_back进ans。但是MLE了,说明采用string并不是一个好方法。下面是MLE的代码:class Solution {public: vector findRepeatedDnaSequences(string s) { vector ans; map mp;原创 2015-09-12 00:10:51 · 2700 阅读 · 0 评论 -
[leetcode] 209 Minimum Size Subarray Sum
(一)O(logN)的解法首先将原数组处理成前项和的形式,这样就保证了数组的有序(注意第一个是0,自己push进去),然后遍历数组,寻找小于等于sum[i]+s的最小的下标,如果找不到,那么break结束。否则继续下去,最后取最小值。class Solution {public: int minSubArrayLen(int s, vector& nums) { vec原创 2015-09-08 23:37:16 · 3281 阅读 · 0 评论 -
[leetcode] 211 Add and Search Word - Data structure design
因为给定了a-z这个范围,并且字符串的添加和查找符合Trie的常用方法,因此考虑使用Trie这种数据结构。然后和普通的Trie不同的是,要匹配正则表达式中的“.”,也就是说在这一层是无法判断沿着拿个结点向下走的,所以要循环这一层的结点,只有这一层所有结果失败后才能返回false,剩下的递推。所以我们采取Trie+回溯法。代码中的searchHelp函数是专门用于回溯的,要求会回溯的掌握比较原创 2015-09-04 01:06:29 · 1778 阅读 · 0 评论 -
[leetcode] 216 Combination Sum III
很基础的一道DFS,开始的时候觉得可能剪枝要处理的好一些,于是我的剪枝是:如果当前的值合适,那么剩下的和一定要大于剩下的个数*1&&小于剩下的个数*9,这虽然不是最优,但是处理起来比较简单,没想到样例只有18组,跑了0ms,数据太水了。class Solution { private: vector >ans; vector v; public: void dfs(i原创 2015-09-03 00:24:16 · 3119 阅读 · 0 评论 -
[leetcode] 222 Count Complete Tree Nodes
1.最容易想到的方法:递归遍历每个点,计算出总的点数,时间复杂度O(n),很不幸,超时了。(不超也说不过去啊==)class Solution {public: int countNodes(TreeNode* root) { if(root==NULL) return 0; int res=0; if(root->le原创 2015-08-31 20:55:06 · 1625 阅读 · 0 评论 -
[leetcode] 240 Search a 2D Matrix II
很经典的一道题,每行由左到右,每列由上到下升序排列,让我们采用高效的算法判断一个值是不是存在。第一种方案:遍历行,若发现行首的元素这个算法的最坏时间复杂度是O(n*logm)。当然如果你对行也进行二分搜索,确定一个搜索的行的范围的话,时间复杂度会更低。class Solution {public: bool searchMatrix(vector >& matrix, int原创 2015-08-19 12:15:38 · 1420 阅读 · 0 评论 -
[leetcode] Bitwise AND of Numbers Range(位运算)
不得不说位运算的应用都是很巧妙的。这道题求一个连续区间整数的与运算的值,突破点在于连续的区间这个特点。我们可以先找几个数看一下规律,2 3 4 5的二进制分别是 10 ,11,100,101,可以发现若m==n,则m为答案;当m!=n时,因为连续的两个数的二进制的最后一位肯定不一样,与的值一定是0,前面相同的部分(1&1=1,0&0=0)保持。所以我们每次先判断,不同的话就右移一位原创 2015-08-14 23:14:50 · 1232 阅读 · 0 评论 -
[leetcode] Product of Array Except Self
(1) 预处理出所有数的乘积,然后每次去除nums[i],可以得到正确的答案数组,但是题目中明确写明without division .,不可行。(2) 预处理出前n项的乘积,放到temp数组中,然后倒着遍历,为了节约空间,我们使用一个Cur变量记录当前后面的乘积。class Solution {public: vector productExceptSelf(vector& n原创 2015-07-22 22:45:36 · 1156 阅读 · 0 评论 -
[leetcode] Palindrome Number(不使用额外空间)
本来判断回文串是一件很容易的事情,只需要反转字符串后在与原字符串相比较即可。这道题目明确说明不能使用额外的空间,那么使用将其分解连接成字符串的方法便不是可行的。只好采用数学的方式: 每次取最高位和最低位相比较,总的位数可以用一个while先处理出来,循环直至取余和除数相等。具体见代码:class Solution {public: bool isPalindrome(int x)原创 2015-07-20 20:10:18 · 1368 阅读 · 0 评论 -
Valid Parentheses (栈的符号匹配)
很简单的利用栈进行括号匹配的题目。当是左边的符号的时候,压进栈中。发现是右边的符号的时候,先判断其是否为空,然后与栈顶元素比较,不等直接return false注意一点就是 最后只有栈中为空的时候才返回true。class Solution {public: bool isValid(string s) { stack sk; int len=原创 2015-07-12 22:28:08 · 1281 阅读 · 0 评论 -
[leetcode] Longest Palindromic Substring 多种解法
很经典的题目,求字符串中的最长回文子串。(1)最朴素的解法 ---暴力 复杂度O(N³)这也是最容易想到的方法,最外层循环枚举起点i,第二层循环从i+1开始向后枚举,第三层判断是不是回文串。最后取最长子串的返回。代码比较简单,这里没有列出。(2)中心扩展法。复杂度O(N²)枚举每一个字符作为中心点向左右扩展。但是这里要注意,对于每一次扩展要分奇偶两种情况。否则可能会漏掉情况。原创 2015-07-16 00:03:10 · 2164 阅读 · 0 评论 -
Leetcode Isomorphic Strings
题意很简单,判断两个字符串是不是同构,也就是说字母之间的映射关系是一对一的,采用map对应即可。注意,要分别对s和t都要判断一遍,否则类似 s="abe", t="cdc"就会判断出错。class Solution {public: bool isIsomorphic(string s, string t) { map mp; int len=s.length(原创 2015-05-16 00:08:20 · 813 阅读 · 0 评论 -
Leetcode Happy Number
这题本来想找数学规律来着,但是没有找到。。(有路过的大牛还请指导)就根据题目来看,要么出现1,返回true退出;要么在循环的过程中出现了以前出现的数(这点题目中给出了描述or it loops endlessly in a cycle which does not include 1. )。所以将过程中出现的数存入set中,每次插入 的时候,如果发现size大小没有变,那么一定是插入了重复原创 2015-05-16 23:40:29 · 838 阅读 · 0 评论 -
Leetcode Number of 1 Bits(位运算)
判断一个无符号整数的二进制中有多少个1。(1)先来一种比较好想到的方法:将数与1进行&运算,若为1则证明最后一位是1,然后再将原来的数字右移一位,依次直到原来的数字为0结束。class Solution {public: int hammingWeight(uint32_t n) { int sum=0; while(n) {原创 2015-05-17 00:27:19 · 942 阅读 · 0 评论 -
【dp】Leetcode House Robber&& House Robber II
很基础的动态规划。因为不能取连续的,所以要么只取第i-1个或者取第i-2和第i个,去最大值,列出状态转移方程即可。class Solution {public: int rob(vector& nums) { int n=nums.size(); if(n==0)//需要特判,否则为0时越界 return 0; els原创 2015-05-18 23:39:21 · 932 阅读 · 0 评论 -
Leetcode Two Sum (数组)
题意: 从一个无序数组中找到两个数(一定存在)使其和等于target,返回两个数的下标号,时间尽可能的优。(1)因为有并且只有一组,我们可以先将数组排序,设置两个指针,一前一后,通过和的不同的情况移动指针,但是因为有了排序的过程,时间复杂度NlogNstruct node{ int value; int indexx;}N[100005];bool comp(node a原创 2015-05-20 00:31:12 · 923 阅读 · 0 评论 -
Leetcode Longest Substring Without Repeating Characters(最长不重复子串)
如题,求一个字符串中的最长不重复子串。采用O(n)的算法,hash[值]=index,设置一个指针指向字符串的首位,遍历,每当发现有重复的字母出现时,则指针指向最近的那个重复字符,记录更新长度。ans设为0,cur设为-1,有效解决空串和单字符的问题。class Solution {public: int lengthOfLongestSubstring(string s) {原创 2015-05-21 23:48:59 · 1111 阅读 · 0 评论 -
LeetCode Reverse Integer (处理溢出)
这道题看上去比较简单,但是需要注意的细节和情况的处理还是很多的。(1) 注意负数(2)注意10,100这类数字的反转(3) 最容易忽视的一点,整型的溢出。(2333333339反转超int)注意我们计算的过程中不需要另外存数字,直接计算就好。处理溢出我们先用long long储存,超int后直接返回0其实我们发现,(1)和(2)都不需要特殊处理,在运算的过程中会自行处理。c原创 2015-05-25 23:25:13 · 1483 阅读 · 0 评论 -
Leetcode Longest Common Prefix (排序进行优化)
写完之后看到网上很多人的做法是暴力匹配,其实不用这样的。我们只要先将字符串排序,那么如果相邻的两个字符串一定前缀匹配度最高,那么我们只需要遍历一遍,每次比较当前字符串和它的前一个字符串的前缀,得出len,然后取所有len中的最小值即可。注意特判size为0和1的情况。时间8msclass Solution {public: string longestCommonPref原创 2015-05-28 16:48:35 · 1115 阅读 · 0 评论 -
Leetcode Count Primes (欧拉线性筛法求素数)
欧拉筛法求素数的时间复杂度已经达到了O(n),是线性的很优秀的算法。有关具体算法的详解请参考我的这一篇博客。下面附上代码:class Solution {public: int countPrimes(int n) { int cnt=0; memset(vis,0,sizeof(vis)); for(int i=2;i<n;i++) { if(!vis原创 2015-05-29 22:54:19 · 4279 阅读 · 0 评论