32.Longest Valid Parentheses
- 难度:hard
- 代码语言:JavaScript
- 时间:17-10-17
题目描述
Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
For "(()"
, the longest valid parentheses substring is "()"
, which has length = 2.
Another example is ")()())"
, where the longest valid parentheses substring is "()()"
, which has length = 4.
相当于说,要从一个由括号组成的字符串中,找到一个最长的正确匹配的子字符串的长度。
解题思路
遍历整个字符串,通过堆栈的方式,每次遍历到
'('
,把下标压入栈中,每次遍历到')'
,从栈中弹出栈顶,并在链表中,把弹出的栈顶指向当前节点。这样可以得到一个链表,相当于记录了一个字符串中,左右括号的匹配情况,比如下面这个字符串,
’))(()())(()‘
通过遍历这个链表,就能找到最长的子字符串
/*** @param {string} s* @return {number}*/var longestValidParentheses = function (s) {var longest = 0var stack = [], match = []for (var j = 0; j < s.length; j++) {if (s[j] == '(') {stack.push(j)} else {var begin = stack.pop()var end = jif(begin != undefined){match[begin] = endmatch[end] = -1}}}var i = 0, length = 0, begin = 0, end = 0while(i < match.length){while(match[i] == undefined && i < match.length){i++}if(match[i] == -1){if(match[i+1] == undefined){end = ilength = end - begin + 1if( length > longest){longest = length}i++} else {i = match[i+1]}} else {begin = ii = match[i]}}return longest};
Substring with Concatenation of All Words
- 难度:hard
- 代码语言:JavaScript
- 时间:17-10-15
题目描述
You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.
For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]
You should return the indices: [0,9]
.
(order does not matter).
解题思路
我的解题思路很简单,因为words
中的每个单词的长度(length)是固定的,所以只要每length长度,对s
进行扫描就行了,扫描到的单词刚好在words里面就把它记录下来即可。这样做的时间复杂度是O(N*M),N是s的长度,M是words的个数。
|
Container With Most Water
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container.
解题思路
最简单的,当然就是穷举算法,当然算法复杂度是$O(n^2)$,具体而言,应该是n+(n-1)+(n-2)+…+1这个虽然可取,但是肯定不是我们这么优秀的人的追求啊,在此也不再赘述
在穷举算法的基础上,进行减支,当然,减支最好的结果就是降低时间复杂度了,当然如果能稍微提点速也是不错的,以下的这个思路就帮我通过了leetcode的测试:
首先需要明白的是,我们的穷举算法中的循环是这个样子的,每次确定水桶左边的一条边,再往后找出右边的那条边
for(var i = 0; i < height.length; i++)for(var j = i; j < height.length; j++)第二条原则,两个水桶,公用其中一条边,那么如果其中一个水桶,底又宽,另外一条边又比较长,那肯定这个桶容得下的水比较多,至少不少。举个例子,如下图,a和c组成的水桶肯定比b和c组成的水桶容的水更多。
基于上面两条,既然我们是从左往右遍历的,那么发现b比a短的那一瞬间,我们就应该抛弃b的这种情况。所以边往下遍历的时候,找出已经遍历过的那些边中最长的,那些比最长边要小的,并且在最长边右边的就不考虑了……
代码如下:
var maxArea = function(height) {var maxArea = 0, maxHeight = 0for(var i = 0; i < height.length; i++){if(height[i] > maxHeight){ // 比较是否比已经遍历过的最长边还要长maxHeight = height[i]for(var j = i; j < height.length; j++){var h = (j - i) * Math.min(height[i], height[j])if(h > maxArea)maxArea = h}}}return maxArea};
最终的理想——$O(n)$,在原来的基础上,我们需要再明确一个原则:当某条线作为矩形(水桶)的边时能构造出的最大的矩形,比另外一个矩形面积还要小的时候,那它肯定不是最大的。当然这条原则显而易见,但是在某种场景下有很大用途。
如下图,四条线的高度按从大到小排序为:c>d>b>a。
明显的是,当a作为水桶的一边时,和d组合才能达到最大容量;
那么如果b&d组成的面积(蓝色部分)大于a&d组成的面积(黄色部分),那么a这条边就可以排除了,因为a作为矩形的一条边时能产生的最大面积都已经小于b的某种情况了。
根据上面这条原理,我们可以设计出一种,从前往后,从后往前同时进行的算法。
b比a短时完全无需考虑了,当b>a时,检查一下b和d构成的面积是否大于当前的最大面积,如果是的话就将b&d的面积设置为最大面积,之后继续往后遍历,直到找到第一条比d还高的边,这就不符合上面提到的那种情况了
于是我们从后往前开始,从d开始往前遍历寻找,这其实除了方向不一样以外,和上面的算法是一样的。
事实证明,这种算法是正确的,附上代码:
var maxArea = function(height) {var maxArea = -1, maxHeight = [-1, -1], i = 0, j = height.length - 1while(i < j){for(; i < j ;){if(height[i] > maxHeight[0]){if(height[i] > height[j])breakmaxHeight[0] = height[i]var area = Math.min(maxHeight[0], height[j]) * (j - i)if(area > maxArea)maxArea = area}i++}for(; j > i;){if(height[j] > maxHeight[1]){if(height[i] < height[j])breakmaxHeight[1] = height[j]var area = Math.min(maxHeight[1], height[i]) * (j - i)if(area > maxArea)maxArea = area}j--}}return maxArea};
Regular Expression Matching
- 难度:Hard
- 代码语言:JavaScript
- 时间:16-11-08
题目描述
Implement regular expression matching with support for'.'
and'*'
.
|
解题思路
递归解法:
- 如果
p
的第二位不是*
,那么说明s
的第一位一定要匹配p
的第一位,那么从p
的第二位和s
的第二位开始再执行这个函数(进行递归),否则返回false
- 如果
p
的第二位是*
,需要一个循环,将s.substring(0), s.substring(1), s.substring(2)...
与p
去掉头两个进行match(递归),直到s.substring(i)
的第一个字符和p
的第一个字符不一样;举个例子:s
是aaabcd
,p
是a*bcd
,那么,要将aabcd
和bcd
比较,不符合的话,再对abcd
和bcd
比较… - 这种解法的算法复杂度,似乎在最差情况下会达到$O(n^2)$
- 如果
其他解法:
暂时还在想..
代码
|
Median of Two Sorted Arrays
- 难度:Hard
- 代码语言:JavaScript
- 时间:16-09-30
题目描述
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n))
.
Example 1:
Example 2:
解题思路
一开始以为是归并排序的一个小小的应用而已,但一直不明白:O(log (m+n))
的时间复杂度怎么达到……后来才明白这个题的恐怖之处就在于此,结题方案是利用二分查找类似的方法,来找到这个值,具体算法比较难写,先挖个坑,后面填上,贴上一个别人的解决方案:
代码
时间复杂度为O(M+N)的算法:
时间复杂度为O(log(m+n))的算法:
先挖坑:
结果
81.90%……玛德其实这个什么卵用都没有!因为即便这么差的算法也能跑这么快?今天以后就不贴了 ZZ;
Longest Substring Without Repeating Characters
- 难度:Medium
- 代码语言:JavaScript
- 时间:16-09-29
题目描述
Given a string, find the length of the longest substring without repeating characters.
Examples:
- Given
"abcabcbb"
, the answer is"abc"
, which the length is 3. - Given
"bbbbb"
, the answer is"b"
, with the length of 1. - Given
"pwwkew"
, the answer is"wke"
, with the length of 3. Note that the answer must be a substring,"pwke"
is a subsequence and not a substring.
PS:最后要求返回的是子字符串的长度,而不是子字符串。
解题思路
这题一眼就能看出来,最快的算法肯定是O(N)。在这个算法当中,有一步是必须的:
- 发现一个字符是否有重复:利用类似哈希表的一个数据结构就能在O(1)时间内发现。
举个例子来说明:
假设字符串是:"abvdfrhvmcvxdcgtew"
不断向下遍历,并且在一个数组(类似哈希表)里面存入已发现的字符最大的下标,假设该数组叫:
charMaxSub
,当遍历到第二个v
之前,就已经存储了:charMaxSub = {a: 0,b: 1,d: 3,f: 4,h: 6,r: 5,v: 2}当找到重复字符
v
时,就会发现,在charMaxSub
里面已经存了v
,所以这个时候就会产生第一个没有重复字符的最长子字符串:"abvdfrh"
。此刻应该把charMaxSub.v
更新为新的下标。- 此时,继续往后遍历,再发现新的没有重复的子字符串,也只能是从第一个
v
后面产生的,所以,可以把第一个v
后面的第一个字符,也就是下标为3的这个当做数组的开始。 - 继续重复以上的环节,一直往后遍历,直到对比出最长的没有重复字符的子字符串。
代码
|
结果
Your runtime beats 43.41% of javascript submissions.
Add Two Numbers
- 难度:Medium
- 代码语言:JavaScript
- 时间:16-09-28
题目描述
You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
解题思路
其实就是一般性的加法运算,就很简单,就是个位和个位相加,向前进位。但是你不能先把两个链表先分别整理成整数,也就是不能把(2 -> 4 -> 3)搞成342,因为可能链表比较长的时候就会比较大,会有case通不过……
这题竟然是medium,值得吐槽……
代码
|
结果
这种算法的效率beats了46.06%的提交者
Two Sum
- 难度:easy
- 代码语言:JavaScript
- 时间:16-09-27
题目描述
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution.
Example:
UPDATE (2016/2/13):
The return format had been changed to zero-based indices. Please read the above updated description carefully.
解题思路
这道题最终的思路就是找到一个时间复杂度为O(N)的算法。
- 一次遍历下去,假设下标为i,每次用target减去数组中对应的那个值nums[i],把差存放在一个新的数组中;
- 遍历的同时,去看看存储差值的那个数组里是否已经包含了当前这个nums[i],如果包含的话,就相当于找到了这一对的值;
- 所以目标是把每次寻找的时间复杂度降低到O(1),这样总体复杂度也就降低到了O[N]。
具体就看代码吧,很简单。
代码
|
结果
37.Sudoku Solver
- 难度:hard
- 代码语言:JavaScript
- 时间:18-04-09
题目描述
Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character '.'
.
You may assume that there will be only one unique solution.
也就是找数独的解,而且保证输入的数独是有唯一解的
解题思路
其实就是个回溯。但是首先可以进行两个预处理。
- 先建立一个set,包含1-9的元素,然后去遍历每一个待填充的格子所在行、所在列和所在的九宫格,从set中删掉那些这些行、列和九宫格里已经填好的元素,得到的最终的set作为该单元格的可能解,假如这个可能解只有一个,那么刚好可以直接填入。
- 经历第一步后,每个待填充的单元格都会有它的可能解了。但可能,某个单元格包含的可能解,该单元格同行的那些待填充的单元格都不包含,那么只能它来填充这个可能解了,于是乎该单元格也被确定下来。同列和同九宫格的那些也一样。
- 在这两个基础上,再进行深度优先搜索的回溯,就会快很多。
|
39.Combination Sum
- 难度:Medium
- 代码语言:JavaScript
- 时间:18-04-10
题目描述
Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
Note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
For example, given candidate set [2, 3, 6, 7]
and target 7
,
A solution set is:
|
给定目标7,要从候选的数组里面选出不同的组合,使得和为7
解题思路
简单想,其实是一个递归,最简单的递归思路如下:
|
上述的解法比较简洁,因为应用了set的特性,但是JavaScript中,set的构建和解构是非常耗时的,我们希望转换成数组的形式:
|
41.First Missing Positive
- 难度:hard
- 代码语言:JavaScript
- 时间:18-04-11
题目描述
Given an unsorted integer array, find the first missing positive integer.
For example,
Given [1,2,0]
return 3
,
and [3,4,-1,1]
return 2
.
Your algorithm should run in O(n) time and uses constant space.
就是找最小的没有在数组中出现的正数。但难点在于如何用O(n)的时间和常数的空间。
解题思路
看到这种题,自然而然第一想法就是去排序,然后遍历就OK。但难点在于O(n)的排序算法
一般的排序算法,最快也得要O(n*logn),比如快排。当然也有一种trick,利用散列,用O(n)的效率就能将它们散列好(具体代码可以看下方),但从中去遍历的效率就和最大值成正比了,况且这种排序方法的空间并不是一个常数空间,需要在遍历数组的时候,不断扩大。
// 简单的排序,效率是常数的,O(max(array)),这里是简单实现,最终结果是不包含重复值的var hashSort = function(array) {let sortedArray = array.reduce((result, num) => {result[num] = truereturn result}, [])return sortedArray.filter(num => !isNaN(num))}但是还好,我们是找最小缺失的正整数,所以这个正整数一定不会大于数组的长度!
当明白了以上这一点之后,也就解决了非常数空间的问题了,于是解决方案如下,效率也极为高效:
/*** @param {number[]} nums* @return {number}*/var firstMissingPositive = function (nums) {let record = []for (let i = 0; i < nums.length; i++) {let num = nums[i]if (num > 0 && num <= nums.length) {record[num] = true}}var i = 1for (; i < record.length; i++) {if (!record[i]) {return i}}return i};
42.Trapping Rain Water
- 难度:hard
- 代码语言:JavaScript
- 时间:18-04-11
题目描述
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1]
, return 6
.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
就是给你一堆黑色的条状图,然后下雨,算出能装满的雨水量。
解题思路
- 假如我们从左往右进行遍历,能装雨水的地方,一定是某根柱子和它右边的第一根不比它矮的柱子之间的部分。于是我们寻找这样的组合即可。
- 但有可能这根柱子右边没有比它高的柱子了,那么从左往右的遍历方法就失效了。故而我们要从右往左再遍历一遍。直到所有的柱子都遍历完。
|
44. Wildcard Matching
- 难度:hard
- 代码语言:JavaScript
- 时间:18-04-14
题目描述
Given an input string (s
) and a pattern (p
), implement wildcard pattern matching with support for '?'
and '*'
.
|
The matching should cover the entire input string (not partial).
Note:
s
could be empty and contains only lowercase lettersa-z
.p
could be empty and contains only lowercase lettersa-z
, and characters like?
or*
.
Example 1:
|
Example 2:
|
Example 3:
|
Example 4:
|
Example 5:
|
问题可以简单表述为正则匹配,*
表示匹配0或多个任意字符,?
表示匹配1个任意字符。字符只包含a-z
。
解题思路
- 我的思路是,在正则表达式中,
*
是一个很特殊的存在,因为它可以匹配[0, Inifinity]
个任意字符,所以要特殊对待。 - 我专门写了一个
findFromS
函数方便调用,用来查找某个字符串str在输入的s中的所有位置,能够处理?
的情况,效率应该是$O(len(s) * len(str))$。 - 首先我们来看头和尾,如果正则表达式的头和尾都不是
*
,那么就需要看看能不能和字符串s的头尾相吻合,如果吻合则p和s都去掉头尾。 - 对于p的中间的部分,我们可以用
*
来分割它们,则会得到一个序列,我们只要去s中寻找,是否有这样的序列即可。
|
49. Group Anagrams
- 难度:Medium
- 代码语言:JavaScript
- 时间:18-05-08
题目描述
Given an array of strings, group anagrams together.
Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],Output:[["ate","eat","tea"],["nat","tan"],["bat"]]Note:
- All inputs will be in lowercase.
- The order of your output does not matter.
找到Anagrams,具体什么叫Anagrams应该在例子中说明的比较清楚。
解题思路
这题思路其实不难,但一直有个瓶颈,关于如何将一个字符串,hash成为一个数字的问题。看了最佳答案,它的hash方法值得学习:
|
用反证法证明其有效性:
假设存在四个质数:$a,b,c,d$,使得$a\times b=c\times d$,显然,这是不可能的,因为如果成立,$a$和$b$就是$c \times d$的公约数,而显然$c \times d$的公约质数只有$c $和$d$,所以不存在$a \times b = c \times d$。
故而不同的质数相乘,一定会得到不一样的解,也就解决了hash过程中collision的问题。