├── 位操作 ├── README.md └── 078.subset[M].md ├── styles └── website.css ├── addcomment.png ├── 链表 ├── gitpush.bat ├── 023. Merge k Sorted Lists [H] │ ├── 1463149101056.png │ ├── 1463149197129.png │ └── 023. Merge k Sorted Lists [H].md ├── 21. Merge Two Sorted Lists.md ├── 024. Swap Nodes in Pairs My Submissions[E].md ├── 019. Remove Nth Node From End of List.md └── 002. Add Two Numbers [M].md ├── 146082035535500.png ├── 146082043110733.png ├── 1461598844843.png ├── 1462450627386.png ├── 1462450863918.png ├── 1460818716_507860.png ├── 数组 ├── 015. 3Sum │ ├── 1460991088774.png │ └── 015. 3Sum.md ├── 016. 3Sum Closest [M] │ ├── Thumbs.db │ ├── 1460991088774.png │ └── 16. 3Sum Closest [M].md ├── 017. Letter Combinations of a Phone Number[M] │ ├── 1461570562032.png │ └── 017. Letter Combinations of a Phone Number[M].md ├── 028. Implement strStr.md ├── 026. Remove Duplicates from Sorted Array[E] │ ├── 026. Remove Duplicates from Sorted Array[E].md │ └── 1463063417666.png ├── 20. Valid Parentheses.md ├── 011. Container With Most Water[M].md ├── 009. Palindrome Number[E].md ├── 027. Remove Element[E].md ├── 001.Two Sum[E].md └── 018. 4Sum[M].md ├── 动态规划 ├── 174. Dungeon Game[H] │ ├── 1473822748993.png │ └── 174. Dungeon Game[H].md ├── 22. Generate Parentheses[M] │ ├── 1462892959966.png │ ├── 1462893036822.png │ └── 22. Generate Parentheses[M].md ├── 010. Regular Expression Matching │ ├── 1461922697867.png │ ├── 1461923613623.png │ ├── 1461923701320.png │ ├── 1461923856937.png │ ├── 1461923916690.png │ ├── 1461923981629.png │ ├── 1460723068367.png │ ├── 1460724147977.png │ ├── 010. Regular Expression Matching.md │ └── 1460724161261.png ├── 053. Maximum Subarray[M].md ├── 120. Triangle[M].md ├── 338. Counting Bits [M].md └── 064. Minimum Path Sum[M].md ├── 分治 └── 004. Median of Two Sorted Arrays[H] │ ├── Thumbs.db │ ├── 1460176468429.png │ ├── 1460176540020.png │ ├── 1461510924594.png │ ├── 1461510936040.png │ └── 004. Median of Two Sorted Arrays[H].md ├── 字符串 ├── 003. Longest Substring Without Repeating Characters[M] │ ├── Thumbs.db │ ├── 1459857033836.png │ ├── 1459857050765.png │ ├── 1459857109997.png │ ├── 1459857137766.png │ ├── 1459857157171.png │ └── 003. Longest Substring Without Repeating Characters[M].md ├── 014. Longest Common Prefix[E].md └── 005. Longest Palindromic [M].md ├── book.json ├── 规律 ├── 292. Nim Game[E].md └── 006.ZigZag Conversion[E].md ├── twopoint.md ├── 二分查找 ├── 035. Search Insert Position[M].md ├── README.md ├── 374. Guess Number Higher or Lower[E].md ├── 033. Search in Rotated Sorted Array[H].md └── 034. Search for a Range[M].md ├── 查表 ├── 013. Roman to Integer2[E].md ├── 013. Roman to Integer[E].md └── 012. Integer to Roman[M].md ├── 数学 ├── 007.Reverse Integer[E].md ├── 029. Divide Two Integers[M].md └── 008.String to Integer —atoi[E].md ├── SUMMARY.md ├── topic_include.md ├── README.md └── 介绍 └── 介绍.md /位操作/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /styles/website.css: -------------------------------------------------------------------------------- 1 | /* CSS for website */ 2 | -------------------------------------------------------------------------------- /addcomment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/addcomment.png -------------------------------------------------------------------------------- /链表/gitpush.bat: -------------------------------------------------------------------------------- 1 | git pull 2 | git add * 3 | git commit -m "add" 4 | git push 5 | -------------------------------------------------------------------------------- /146082035535500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/146082035535500.png -------------------------------------------------------------------------------- /146082043110733.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/146082043110733.png -------------------------------------------------------------------------------- /1461598844843.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/1461598844843.png -------------------------------------------------------------------------------- /1462450627386.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/1462450627386.png -------------------------------------------------------------------------------- /1462450863918.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/1462450863918.png -------------------------------------------------------------------------------- /1460818716_507860.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/1460818716_507860.png -------------------------------------------------------------------------------- /数组/015. 3Sum/1460991088774.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/数组/015. 3Sum/1460991088774.png -------------------------------------------------------------------------------- /数组/016. 3Sum Closest [M]/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/数组/016. 3Sum Closest [M]/Thumbs.db -------------------------------------------------------------------------------- /动态规划/174. Dungeon Game[H]/1473822748993.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/174. Dungeon Game[H]/1473822748993.png -------------------------------------------------------------------------------- /数组/016. 3Sum Closest [M]/1460991088774.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/数组/016. 3Sum Closest [M]/1460991088774.png -------------------------------------------------------------------------------- /分治/004. Median of Two Sorted Arrays[H]/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/分治/004. Median of Two Sorted Arrays[H]/Thumbs.db -------------------------------------------------------------------------------- /动态规划/22. Generate Parentheses[M]/1462892959966.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/22. Generate Parentheses[M]/1462892959966.png -------------------------------------------------------------------------------- /动态规划/22. Generate Parentheses[M]/1462893036822.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/22. Generate Parentheses[M]/1462893036822.png -------------------------------------------------------------------------------- /链表/023. Merge k Sorted Lists [H]/1463149101056.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/链表/023. Merge k Sorted Lists [H]/1463149101056.png -------------------------------------------------------------------------------- /链表/023. Merge k Sorted Lists [H]/1463149197129.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/链表/023. Merge k Sorted Lists [H]/1463149197129.png -------------------------------------------------------------------------------- /分治/004. Median of Two Sorted Arrays[H]/1460176468429.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/分治/004. Median of Two Sorted Arrays[H]/1460176468429.png -------------------------------------------------------------------------------- /分治/004. Median of Two Sorted Arrays[H]/1460176540020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/分治/004. Median of Two Sorted Arrays[H]/1460176540020.png -------------------------------------------------------------------------------- /分治/004. Median of Two Sorted Arrays[H]/1461510924594.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/分治/004. Median of Two Sorted Arrays[H]/1461510924594.png -------------------------------------------------------------------------------- /分治/004. Median of Two Sorted Arrays[H]/1461510936040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/分治/004. Median of Two Sorted Arrays[H]/1461510936040.png -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1461922697867.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/010. Regular Expression Matching/1461922697867.png -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1461923613623.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/010. Regular Expression Matching/1461923613623.png -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1461923701320.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/010. Regular Expression Matching/1461923701320.png -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1461923856937.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/010. Regular Expression Matching/1461923856937.png -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1461923916690.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/010. Regular Expression Matching/1461923916690.png -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1461923981629.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/动态规划/010. Regular Expression Matching/1461923981629.png -------------------------------------------------------------------------------- /数组/017. Letter Combinations of a Phone Number[M]/1461570562032.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/数组/017. Letter Combinations of a Phone Number[M]/1461570562032.png -------------------------------------------------------------------------------- /字符串/003. Longest Substring Without Repeating Characters[M]/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/字符串/003. Longest Substring Without Repeating Characters[M]/Thumbs.db -------------------------------------------------------------------------------- /字符串/003. Longest Substring Without Repeating Characters[M]/1459857033836.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/字符串/003. Longest Substring Without Repeating Characters[M]/1459857033836.png -------------------------------------------------------------------------------- /字符串/003. Longest Substring Without Repeating Characters[M]/1459857050765.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/字符串/003. Longest Substring Without Repeating Characters[M]/1459857050765.png -------------------------------------------------------------------------------- /字符串/003. Longest Substring Without Repeating Characters[M]/1459857109997.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/字符串/003. Longest Substring Without Repeating Characters[M]/1459857109997.png -------------------------------------------------------------------------------- /字符串/003. Longest Substring Without Repeating Characters[M]/1459857137766.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/字符串/003. Longest Substring Without Repeating Characters[M]/1459857137766.png -------------------------------------------------------------------------------- /字符串/003. Longest Substring Without Repeating Characters[M]/1459857157171.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hk029/leetbook/HEAD/字符串/003. Longest Substring Without Repeating Characters[M]/1459857157171.png -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "katex", 4 | "duoshuo" 5 | ], 6 | "pluginsConfig": { 7 | "duoshuo": { 8 | "short_name": "leetbook", 9 | "theme": "default" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /数组/028. Implement strStr.md: -------------------------------------------------------------------------------- 1 | 28. Implement strStr() 2 | --- 3 | #问题 4 | Implement strStr(). 5 | 6 | Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. 7 | 8 | #思路 9 | ``` 10 | public class Solution { 11 | public int strStr(String haystack, String needle) { 12 | if(needle.length() == 0) return 0; 13 | int h ,t; 14 | for(h = 0;h <= haystack.length() - needle.length();h++) 15 | { 16 | for(t = 0;t < needle.length();t++) 17 | if(haystack.charAt(h+t) != needle.charAt(t)) break; 18 | if(t == needle.length()) 19 | return h; 20 | } 21 | return -1; 22 | } 23 | } 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /规律/292. Nim Game[E].md: -------------------------------------------------------------------------------- 1 | ##292. Nim Game[E] 2 | --- 3 | #题目 4 | You are playing the following Nim Game with your friend: There is a heap of stones on the table, each time one of you take turns to remove 1 to 3 stones. The one who removes the last stone will be the winner. You will take the first turn to remove the stones. 5 | 6 | Both of you are very clever and have optimal strategies for the game. Write a function to determine whether you can win the game given the number of stones in the heap. 7 | 8 | For example, if there are 4 stones in the heap, then you will never win the game: no matter 1, 2, or 3 stones you remove, the last stone will always be removed by your friend. 9 | 10 | #分析 11 | 1. 只要能被4整除,你就输了。因为不论你怎么拿,对方都会凑到4。 12 | 2. 如果不能被4整除,那你第一次把余数拿了,然后你模仿上面的策略,你就赢了。 13 | 14 | #代码 15 | ```python 16 | return bool(n%4) 17 | ``` 18 | -------------------------------------------------------------------------------- /twopoint.md: -------------------------------------------------------------------------------- 1 | # 双指针 2 | 3 | ## 介绍 4 | > 开始,这章的题目是叫“数组”,但是,目前更名为双指针,这是因为我发现凡是数组的题目,大部分都是利用双指针去解决问题。 5 | 6 | 双指针,顾名思义,就是利用两个指针去遍历数组,一般来说,遍历数组采用的是单指针(index)去遍历,两个指针一般是在有序数组中使用,一个放首,一个放尾,同时向中间遍历,直到两个指针相交,完成遍历,时间复杂度也是O(n)。 7 | ## 用法 8 | 一般会有两个指针`front`,`tail`。分别指向开始和结束位置。 9 | ``` 10 | front = 0; 11 | tail = A.length()-1 12 | ``` 13 | 一般循环结束条件采用的是判断两指针是否相遇 14 | ``` 15 | while(fron < tail) 16 | { 17 | …… 18 | } 19 | ``` 20 | 对于in place交换的问题,循环结束条件一般就是其中一个指针遍历完成。 21 | 22 | ## 使用范围 23 | 一般双指针在有序数组中使用的特别多。(部分情况下,未排序数组也有应用) 24 | 一般用来解决下列问题(陆续补充中): 25 | ### 1. 两数求和 26 | 27 | 一般这种问题是问,寻找两个数的和为一个特定的值(比如后面的N SUM问题),这时候,如果数组有序,我们采用两个指针,分别从前和后往中间遍历,front移动和增大,tail移动和减小,通过特定的判断,可以求出特定的和。 28 | 29 | 时间复杂度为O(n),如果用双重循环则要O(n^2)。 30 | 31 | ### 2. in place交换 32 | 33 | 数组的in place(就地)交换一般得用双指针,不然数组中添加或删除一个元素,需要移动大量元素。 34 | 35 | 这时候,一般是一个指针遍历,一个指针去找可以用来交换的元素。 -------------------------------------------------------------------------------- /字符串/014. Longest Common Prefix[E].md: -------------------------------------------------------------------------------- 1 | 2 | 014. Longest Common Prefix[E] 3 | --- 4 | 5 | #问题 6 | Write a function to find the longest common prefix string amongst an array of strings. 7 | 8 | Subscribe to see which companies asked this question 9 | 10 | #思路 11 | 这个没啥思路的,怎么都要两重循环,因为是最长公共子串,随便找一个(一般是第一个作为基准),然后拿拿的首部慢慢去匹配后面的字符串就行了。 12 | ```java 13 | public class Solution { 14 | public String longestCommonPrefix(String[] strs) { 15 | String s = ""; 16 | if(strs.length == 0) 17 | return ""; 18 | for(int i = 0; i < strs[0].length();i++) 19 | { 20 | char c = strs[0].charAt(i); 21 | for(int j = 1;j < strs.length;j++) 22 | { 23 | if(i >= strs[j].length() || strs[j].charAt(i) != c) 24 | return s; 25 | } 26 | s += c; 27 | } 28 | return s; 29 | } 30 | } 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /二分查找/035. Search Insert Position[M].md: -------------------------------------------------------------------------------- 1 | # 问题 2 | 3 | Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. 4 | 5 | You may assume no duplicates in the array. 6 | 7 | 8 | 9 | Here are few examples. 10 | 11 | > [1,3,5,6], 5 → 2 12 | > 13 | > [1,3,5,6], 2 → 1 14 | > 15 | > [1,3,5,6], 7 → 4 16 | > 17 | > [1,3,5,6], 0 → 0 18 | 19 | 20 | 21 | # 思路 22 | 23 | 这个问题的思路很简单,就是二分查找,而且直接套用框架就行了 24 | 25 | 26 | 27 | # 代码 28 | 29 | ```java 30 | public class Solution { 31 | public int searchInsert(int[] nums, int target) { 32 | int st,ed,mid; 33 | st = 0; 34 | ed = nums.length; 35 | while(st < ed) 36 | { 37 | mid = st + (ed - st)/2; 38 | if(nums[mid] < target) 39 | st = mid+1; 40 | else 41 | ed = mid; 42 | } 43 | return st; 44 | } 45 | } 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /查表/013. Roman to Integer2[E].md: -------------------------------------------------------------------------------- 1 | 013. Roman to Integer 2 | --- 3 | 4 | #问题 5 | Given a roman numeral, convert it to an integer. 6 | 7 | Input is guaranteed to be within the range from 1 to 3999. 8 | 9 | Subscribe to see which companies asked this question 10 | 11 | #思路 12 | 首先要知道罗马数字的规律: 13 | 14 | |Symbol |Value| 15 | |-|-| 16 | |I | 1| 17 | |V | 5 18 | |X |10 19 | |L |50 20 | |C | 100 21 | |D| 500 22 | |M| 1,000 23 | 24 | 然后还有一个规则是,罗马数字从左自右相加,但是如果小数字A在大数字B之前,表示B-A 25 | 26 | VI = 5+1 = 6 27 | IV = 5-1 = 4 28 | 29 | 因此,利用2个变量保存当前数字和之前的数字就行了。因为这题很简单,用python比较方便,我就用python做的 30 | 31 | ```python 32 | class Solution(object): 33 | def romanToInt(self, s): 34 | sum=0 35 | pre = 2000 36 | cur = 0 37 | Map = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000} 38 | for i in range(len(s)): 39 | cur = Map[s[i]] 40 | sum = sum+Map[s[i]] 41 | if cur > pre : 42 | sum = sum-2*pre 43 | pre = cur 44 | return sum 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /查表/013. Roman to Integer[E].md: -------------------------------------------------------------------------------- 1 | 013. Roman to Integer 2 | --- 3 | 4 | #问题 5 | Given a roman numeral, convert it to an integer. 6 | 7 | Input is guaranteed to be within the range from 1 to 3999. 8 | 9 | Subscribe to see which companies asked this question 10 | 11 | #思路 12 | 首先要知道罗马数字的规律: 13 | 14 | |Symbol |Value| 15 | |-|-| 16 | |I | 1| 17 | |V | 5 18 | |X |10 19 | |L |50 20 | |C | 100 21 | |D| 500 22 | |M| 1,000 23 | 24 | 然后还有一个规则是,罗马数字从左自右相加,但是如果小数字A在大数字B之前,表示B-A 25 | 26 | VI = 5+1 = 6 27 | IV = 5-1 = 4 28 | 29 | 因此,利用2个变量保存当前数字和之前的数字就行了。因为这题很简单,用python比较方便,我就用python做的 30 | 31 | ```python 32 | class Solution(object): 33 | def romanToInt(self, s): 34 | sum=0 35 | pre = 2000 36 | cur = 0 37 | Map = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000} 38 | for i in range(len(s)): 39 | cur = Map[s[i]] 40 | sum = sum+Map[s[i]] 41 | if cur > pre : 42 | sum = sum-2*pre 43 | pre = cur 44 | return sum 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /动态规划/053. Maximum Subarray[M].md: -------------------------------------------------------------------------------- 1 | 053. Maximum Subarray[M] 2 | --- 3 | ## 题目 4 | Find the contiguous subarray within an array (containing at least one number) which has the largest sum. 5 | 6 | For example, given the array` [-2,1,-3,4,-1,2,1,-5,4]`, 7 | the contiguous subarray `[4,-1,2,1]` has the largest sum = 6. 8 | 9 | 即求一个整数数组中的和最大的连续子数组问题 10 | 11 | 12 | ## 思路 13 | 首先,这个问题可以用枚举来求,比较容易想到 i (0 ... n-1), j (0 .. n-1),然后每次求和的时候,用个巧办法,不用再次循环: 14 | - j 移动的时候把当前j所在的值加到和上 15 | - i 移动的时候把i之前的值减去。 16 | 时间复杂度O(N^2) 17 | 18 | ```java 19 | public class Solution { 20 | public int maxSubArray(int[] nums) { 21 | int sum ,maxsum; 22 | maxsum = nums[0]; 23 | for(int i = 0;i < nums.length;i++) 24 | { 25 | sum = 0; 26 | for(int j = i;j < nums.length;j++) 27 | { 28 | sum += nums[j]; 29 | maxsum = sum>maxsum?sum:maxsum; 30 | } 31 | } 32 | return maxsum; 33 | } 34 | } 35 | ``` 36 | 37 | ## D&C 38 | 之前的枚举的算法可以,但是时间复杂度太高会超时,于是继续优化。有人提出了D&C算法 39 | 把数组分成差不多相等的两部分,最长数组要不在左边,要不在右边,要不在中间。 40 | 分好分,就是2分,关键是怎么合。 41 | 合的话就是左边的最大值和右边的最大值比较,然后再跟合起来后中间的最大值比较。 42 | 中间的最大值求法O(n): 43 | - 左边的最大值不断+右边的值 44 | - 右边最大值不断+左边的值 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /数组/026. Remove Duplicates from Sorted Array[E]/026. Remove Duplicates from Sorted Array[E].md: -------------------------------------------------------------------------------- 1 | 26. Remove Duplicates from Sorted Array[E] 2 | --- 3 | 4 | #问题 5 | Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. 6 | 7 | Do not allocate extra space for another array, you must do this in place with constant memory. 8 | 9 | For example, 10 | Given input array nums = [1,1,2], 11 | 12 | Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the new length. 13 | 14 | #思路 15 | 这题因为是排序好的,所以很容易做。这里关键点是"删除多余元素"这句话,这里其实不是真的删除,因为题目要求不能用额外的空间,所以最好的思路是替换。题目也说了“It doesn't matter what you leave beyond the new length.”,所以我们只要把后面的元素放到前面来就行了。 16 | 17 | 这里用2个指针: 18 | - 1个指针i从1移动到length 19 | - 1个指针newlen记录不重复的个数,只有出现不重复的时候它才能+1 20 | ![Alt text](./1463063417666.png) 21 | 22 | ```java 23 | public class Solution { 24 | public int removeDuplicates(int[] nums) { 25 | if(nums.length < 2) return nums.length; 26 | int newlen = 1; 27 | for(int i = 1;i < nums.length;i++) 28 | {``` 29 | if(nums[i] != nums[i-1]) nums[newlen++] = nums[i]; 30 | } 31 | return newlen; 32 | } 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /二分查找/README.md: -------------------------------------------------------------------------------- 1 | ## 标准二分的框架 2 | 3 | ```java 4 | while(st < ed) 5 | 6 | { 7 | 8 |     int mid= st  + (ed-st)/2; 9 | 10 |     if( r[mid] < target) 11 | 12 |         st = mid+1; 13 | 14 |     else 15 | 16 |         ed = mid; 17 | 18 | } 19 | 20 | return st; 21 | ``` 22 | 23 | ## 二分有几个关键点需要注意: 24 | 25 | 1. 二分的关键就是st和ed两个指针如何移动。需要记住的是,**st只会往大的方向移动,ed只会往小方向移动。** 26 | 2. mid= st  + (ed-st)/2 而不用 mid = (st + ed) / 2 是因为后面的情况当**st+ed很大时可能会产生溢出。** 27 | 3. 注意避免死循环(一般就考虑最后两个数的极端情况): 28 | - 当`mid = st  + (ed-st)/2 ` 时,mid偏向左边(一般求小于等于target的数),所以st必须移动`st = mid+1`,否则就可能会死循环。 29 | - 当`mid = st  + (ed-st)/2 + 1`,mid偏向右边(一般是求大于等于target的数),所以ed必须移动`ed = mid -1`,否则可能死循环 30 | 31 | 32 | 4. 一般来说,如果是求恰好找到的,可以多加一个等于的时候退出 33 | 5. 有时候,我们不好判断到底判断条件里`<`还是`<=`的时候,可以把条件限定在2个数A,B(一般来说,此时的mid = A)和target: 34 | - A(mid) < target,我们需要st还是ed移动 35 | - A(mid) = target,我们需要st还是ed移动 36 | 37 | ## 二分相关的题目 38 | 39 | 注意一般二分查找前提是**有序**,要不是题目已经确保有序了,要不就是自己先做一个排序。 40 | 41 | 42 | 43 | 一般有几种: 44 | 45 | ### 猜数问题 (374题) 46 | 47 | 这种题目一般是说找到里面特定的数字,这个数字是确定存在的,所以肯定会有一个一定匹配的问题,所以一般我们在判断条件中把`if(r[mid] == target)` 单独提出来。 48 | 49 | 50 | 51 | ### 找位置 (35题) 52 | 53 | 这类题目一般是说找到一个数它应该在数组中的位置,就是完整的套用框架。 54 | 55 | 56 | 57 | ### 找边界(34题) 58 | 59 | 这类题目有点麻烦,它需要用两次分别找左右边界。这里就需要考虑里面**可能有和目标数相同的数**。这时候就要特别注意是使用`<=`还是`<`,而在找右边界的时候,需要移动`ed`,这时候`mid`在原来的基础要+1(看注意3) 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /数组/20. Valid Parentheses.md: -------------------------------------------------------------------------------- 1 | 20. Valid Parentheses 2 | --- 3 | #问题 4 | Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. 5 | 6 | The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not. 7 | 8 | #思路 9 | 这道题很简单,就是一个经典的栈的例子——表达式中的括号符号匹配。 10 | - 遇见了左括号就进栈 11 | - 遇见了右括号就出栈 12 | - 如果栈为空,出错 13 | - 如果出栈元素不是匹配的括号,出错 14 | 15 | 这里解决出括号匹配用了一个小tick,就是利用ASCII码,匹配的括号的ascii码都不会相差太远 16 | - '(' ')' 相差1 17 | - '[' ']' '{' '}' 相差2 18 | 19 | 20 | ```java 21 | public class Solution { 22 | public boolean isValid(String s) { 23 | if(s.length() == 0) 24 | return false; 25 | Stack stack = new Stack(); // 创建堆栈对象 26 | for(int i = 0;i < s.length(); i++) 27 | { 28 | if(s.charAt(i) == '(' || s.charAt(i) == '[' || s.charAt(i) == '{') 29 | stack.push(s.charAt(i)); 30 | if(s.charAt(i) == ')' || s.charAt(i) == ']' || s.charAt(i) == '}') 31 | { 32 | if(stack.empty()) return false; 33 | char out = stack.pop(); 34 | if(out - s.charAt(i) > 2) 35 | return false; 36 | } 37 | } 38 | if(stack.empty()) 39 | return true; 40 | return false; 41 | } 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /二分查找/374. Guess Number Higher or Lower[E].md: -------------------------------------------------------------------------------- 1 | # 问题: 2 | We are playing the Guess Game. The game is as follows: 3 | I pick a number from 1 to n. You have to guess which number I picked. 4 | Every time you guess wrong, I'll tell you whether the number is higher or lower. 5 | You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0): 6 | -1 : My number is lower 7 | 1 : My number is higher 8 | 0 : Congrats! You got it! 9 | 10 | Example: 11 | n = 10, I pick 6. 12 | Return 6. 13 | 14 | # 思路 15 | 注意,这里有几个陷阱,一是你要理解`my`的含义,它的`my`是指的`出题人`,而我们是解题人,所以如果返回-1,说明它的数小,我们猜的数大,这里一定要理解! 16 | 17 | 这是一个经典的二分题目,很容易套用二分查找的公式写出来: 18 | ```java 19 | public class Solution extends GuessGame { 20 | public int guessNumber(int n) { 21 | int st = 1, ed = n; 22 | while(st < ed) 23 | { 24 | int mid = (st + ed) / 2; 25 | if(guess(mid) == 0) 26 | return mid; 27 | else if(guess(mid) < 0) // the number is too large 28 | ed = mid-1; 29 | else 30 | st = mid+1; 31 | } 32 | return st; 33 | } 34 | } 35 | 36 | ``` 37 | 看上去没问题,但是实际上有潜在的危险,比如这个例子就A不过去: 38 | 39 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1474187361233) 40 | 41 | 为什么,因为`int mid = (st + ed) / 2;`可能会由于(st+ed)产生溢出!! 42 | 43 | 所以,为了解决这个问题,推荐把mid的写法写成下面的格式: 44 | 45 | ``` 46 | int mid = st + (ed - st) / 2; 47 | ``` 48 | 49 | 然后再A就能通过 -------------------------------------------------------------------------------- /数组/011. Container With Most Water[M].md: -------------------------------------------------------------------------------- 1 | 011. Container With Most Water 2 | --- 3 | #问题 4 | 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. 5 | 6 | Note: You may not slant the container. 7 | 8 | #思路 9 | 首先要明确一个我之前一直理解错的,它的题目是随意找2个木板构成木桶,容量最大,我之前以为是所有的木板已经在它的位置上了,然后找其中容量最大的——你加的水是可以漫过中间比较短的板子的。 10 | 11 | 如果按题意来,就简单了。 12 | 13 | 我们用两个指针来限定一个水桶,left,right。 14 | h[i]表示i木板高度。 15 | Vol_max表示木桶容量最大值 16 | >由于桶的容量由最短的那个木板决定: 17 | Vol = min(h[left],h[right]) * (right - left) 18 | 19 | - left和right分别指向两端的木板。 20 | - left和right都向中央移动,每次移动left和Right中间高度较小的(因为反正都是移动一次,宽度肯定缩小1,这时候只能指望高度增加来增加容量,肯定是替换掉高度较小的,才有可能找到更大的容量。) 21 | - 看新桶子的容量是不是大于Vol_max,直到left和right相交。 22 | 23 | 24 | 代码如下: 25 | ```java 26 | public class Solution { 27 | public int maxArea(int[] height) { 28 | int l = 0,r = height.length-1; 29 | int i = height[l] > height[r] ? r:l; 30 | int vol,vol_max = height[i]*(r-l); 31 | while(l < r) 32 | { 33 | if(height[l] < height[r]) l++; 34 | else r--; 35 | vol = Math.min(height[l],height[r]) * (r - l); 36 | if(vol > vol_max) vol_max = vol; 37 | } 38 | return vol_max; 39 | } 40 | } 41 | 42 | ``` 43 | 44 | 45 | -------------------------------------------------------------------------------- /链表/21. Merge Two Sorted Lists.md: -------------------------------------------------------------------------------- 1 | 21. Merge Two Sorted Lists 2 | --- 3 | #问题 4 | Merge two sorted linked lists and return it as a new list. 5 | 6 | #思路 7 | 这个题目很简单也有几个可以考虑的思路,一个是比较直接的方式,重新构造链表,一种是利用递归 8 | 9 | 10 | #思路1 :用新的链表 11 | 这里用了一个新的节点了保存结果的链表,这里为了方便链表的扩充,增加一个临时的节点变量(否则每次加入都要遍历到尾部) 12 | ```java 13 | public class Solution { 14 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 15 | ListNode result = new ListNode(0); 16 | ListNode tmp = result; 17 | while(l1 != null || l2 != null) 18 | { 19 | if(l2 == null || (l1 != null && l1.val <= l2.val)) 20 | { 21 | tmp.next = l1; 22 | l1 = l1.next; 23 | } 24 | else 25 | { 26 | tmp.next = l2; 27 | l2 = l2.next; 28 | } 29 | tmp = tmp.next; 30 | } 31 | return result.next; 32 | } 33 | } 34 | 35 | ``` 36 | 37 | 38 | #思路2:递归方案 39 | 在很多时候,递归的方案可以提供一种清晰简单的解决方案,代码也更精炼。但是递归有个问题就是容易出现堆栈溢出的问题。 40 | ```java 41 | public: 42 | ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { 43 | if(l1 == NULL) return l2; 44 | if(l2 == NULL) return l1; 45 | 46 | if(l1->val < l2->val) { 47 | l1->next = mergeTwoLists(l1->next, l2); 48 | return l1; 49 | } else { 50 | l2->next = mergeTwoLists(l2->next, l1); 51 | return l2; 52 | } 53 | } 54 | }; 55 | 56 | ``` 57 | 58 | -------------------------------------------------------------------------------- /数组/009. Palindrome Number[E].md: -------------------------------------------------------------------------------- 1 | 009. Palindrome Number[E] 2 | --- 3 | #问题: 4 | Determine whether an integer is a palindrome. Do this without extra space. 5 | 6 | #思路 7 | 这里说不用额外的空间意思是不用O(n)的空间,O(1)的还是可以用的,不然循环都不好写。。 8 | 9 | ##思路1 10 | 简单的思路 就是把数字逆转,然后判断逆转后的数字跟原来数字是不是一样的。 11 | 12 | ```c++ 13 | class Solution { 14 | public: 15 | bool isPalindrome(int x) { 16 | if(x < 0) return false; 17 | int r=0,t; 18 | t = x; 19 | while(t != 0) 20 | { 21 | r =r*10 + t%10; 22 | t /=10; 23 | } 24 | return r == x; 25 | 26 | } 27 | }; 28 | ``` 29 | ##思路2 30 | 但是其实,不用把数字逆转完再判断,因为如果是回文数字,那么只要逆转一半看是否满足回文条件就行了。 31 | 32 | 设新数为r,原来数为x,每次: 33 | 34 | x = x/10,r = r*10 + x%10; 35 | 36 | - 如何到一半停止? 37 | - 如果x <= r时可以停止了(至少到了一半) 38 | - 如果是偶数长度,并且是回文,那么刚好可以到x == r 39 | - 如果为奇数长度,并且是回文,那么x < r,这时候r刚好比x多一位数 40 | 41 | - 停止后判断是否是回文 42 | - 如果是偶数长度,很简单判断 r == x 43 | - 如果是奇数长度,要判断 r/10 == x 44 | 45 | 注意:这里有一些小问题。 46 | - 当尾数为0的情况。尾数为0会导致r的增长少1位数(因为0*10 = 0)。 47 | 比如110不是回文,最后停止r = 1 x =1 但是 r == x 48 | 49 | 50 | - 当数字小于0的时候,也是不满足回文的条件的。 51 | 52 | ```c++ 53 | class Solution { 54 | public: 55 | bool isPalindrome(int x) { 56 | if(x < 0 || (x != 0 && x %10 ==0)) return false; 57 | int r = 0; 58 | while(x > r) 59 | { 60 | r =r*10 + x%10; 61 | x /=10; 62 | } 63 | return (r == x) || (r/10 == x); 64 | 65 | } 66 | }; 67 | ``` 68 | 69 | -------------------------------------------------------------------------------- /动态规划/120. Triangle[M].md: -------------------------------------------------------------------------------- 1 | 120. Triangle[M] 2 | --- 3 | 4 | #题目 5 | Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below. 6 | 7 | For example, given the following triangle 8 | [ 9 | [2], 10 | [3,4], 11 | [6,5,7], 12 | [4,1,8,3] 13 | ] 14 | The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11). 15 | 16 | Note: 17 | Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle. 18 | 19 | #思路 20 | 如图分析: 21 | $d(0,1) = Path[0,1] + min(d(1,1),d(1,2))$
22 | $d(1,1) = Path[1,1] + min(d(2,1),d(2,2))$
23 | $d(1,2) = Path[1,2] + min(d(2,2),d(2,3))$
24 | $……$
25 | $d(3,1) = 4$
26 | $d(3,2) = 1$
27 | $d(3,3) = 8$
28 | $d(3,4) = 3$
29 | 我们从底层往上走,每走一层,都是到这一层的最短路径距离。所以,我们每次只用保存到这一层每个元素的最短路径距离即可。也就是说,对于n层,我们最多只需要n个额外空间。 30 | - 最底层: $[4,1,8,3]$
31 | - 向上走:$[6+1,5+1,7+3] = [7,6,10]$
32 | - 继续:$[3+6,4+6] = [9,10]$
33 | - 最后:$[2+9] = [11]$
34 | 35 | #代码 36 | ```c++ 37 | class Solution { 38 | public: 39 | int minimumTotal(vector>& triangle) { 40 | vector min_path(triangle.back()); 41 | for(int i = triangle.size()-2;i>=0; i--) 42 | { 43 | for(int j = 0;j < triangle[i].size();j++) 44 | { 45 | min_path[j] = min(min_path[j],min_path[j+1]) + triangle[i][j]; 46 | } 47 | } 48 | return min_path[0]; 49 | } 50 | }; 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /数组/027. Remove Element[E].md: -------------------------------------------------------------------------------- 1 | 027. Remove Element[E] 2 | --- 3 | #问题 4 | Given an array and a value, remove all instances of that value in place and return the new length. 5 | 6 | Do not allocate extra space for another array, you must do this in place with constant memory. 7 | 8 | The order of elements can be changed. It doesn't matter what you leave beyond the new length. 9 | 10 | >Example: 11 | Given input array nums = [3,2,2,3], val = 3 12 | 13 | Your function should return length = 2, with the first two elements of nums being 2. 14 | 15 | #思路 16 | 和之前的那道题很像,凡是涉及in place交换的都可以考虑用两指针,一次扫描完成。 17 | 由于这里说了可以交换元素的位置,那么就方便了,我们可以用后面的元素来替换前面的元素,这样就不用交换整个数组。 18 | 19 | 两个指针front和tail,分别从前后向中间扫描,当两个指针相遇则结束。 20 | - 如果fron < tail: 21 | - 移动front,如果遇到了A[front] `==` val的,暂停 22 | - 移动tail,如果遇到了A[tail]`!=`val的,把值复制给A[front] 23 | 24 | 25 | ```java 26 | public class Solution { 27 | public int removeElement(int[] nums, int val) { 28 | int front = 0,tail = nums.length-1; 29 | while(front <= tail) 30 | { 31 | if(nums[front] == val && nums[tail] != val) 32 | { 33 | nums[front] = nums[tail]; 34 | nums[tail] = val; 35 | } 36 | if(nums[front] != val) front++; 37 | if(nums[tail] == val) tail--; 38 | } 39 | return tail+1; 40 | } 41 | } 42 | ``` 43 | 44 | 可以参考`daxianji007 `更加巧妙的代码:这里用一个变量存储不一样的个数,由于题目里只用前index个与val不一样就行,后面的不用考虑,所以每次遇到一个不一样的值,就把它插到前面就好了。 45 | ``` 46 | int removeElement(int A[], int n, int elem) 47 | { 48 | int begin=0; 49 | for(int i=0;i P(new_len,1); 19 | string new_str(new_len-1,'#'); 20 | //生成新串,把所有的字符串通过’#’扩展成奇数 21 | for(int i = 0;i < s.length();i++) 22 | { 23 | new_str[2*i+1] = s[i]; 24 | } 25 | new_str = '$'+new_str +='\0'; //防止越界 26 | //manacher算法 27 | for(int i=1;i < new_len; i++) 28 | { 29 | if(i < bound) 30 | { 31 | P[i] = min(bound-i,P[2*id-i]); //如果在范围内,找对称面的P[id-(i-id)]和max_pos-i的最小值 32 | } 33 | while(new_str[i-P[i]] == new_str[i+P[i]])//查找以这个字符为中心的回文串 34 | { 35 | P[i]++; 36 | } 37 | //更新id和bound 38 | if(i+P[i] > bound) 39 | { 40 | bound = i+P[i]; 41 | id = i; 42 | } 43 | 44 | max_pos = P[i] > P[max_pos]?i:max_pos; 45 | } 46 | int len = P[max_pos]-1; 47 | int start = (max_pos-P[max_pos])/2; 48 | return s.substr(start,len); 49 | } 50 | }; 51 | 52 | 53 | ``` -------------------------------------------------------------------------------- /动态规划/338. Counting Bits [M].md: -------------------------------------------------------------------------------- 1 | ##338. Counting Bits [M] 2 | --- 3 | 4 | #题目 5 | Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array. 6 | 7 | >Example: 8 | For num = 5 you should return [0,1,1,2,1,2]. 9 | 10 | Follow up: 11 | 1. It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass 12 | 2. Space complexity should be O(n). 13 | 3. Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language. 14 | 15 | 16 | #思路 17 | 这是一个比较简单的动规题目,就是统计二进制数的1个个数,通过观察可以发现二进制数有很多规律在里面 18 | 19 | |十进制|二进制| 20 | |-:-|-:-| 21 | |1 | 1 22 | |2 | 10 23 | |3 | 11 24 | |4 | 100 25 | |8 | 1000 26 | |9 | 10001 27 | 28 | 29 | 可以看见,当二进制位数多1位的时候,高位为1,剩下的和之前的是一样的。 30 | >list[i] = list[i%n]+1 //n = floor(log(i)) 31 | 32 | >list[2] = list[2%2]+1 33 | > 34 | >list[5] = list[5%4]+1 35 | > 36 | >list[12] =list[12%8]+1 37 | 38 | #代码 39 | ```c++ 40 | class Solution { 41 | public: 42 | vector countBits(int num) { 43 | vector ones(num+1,0); 44 | int base = 1; 45 | for(int i = 1; i <= num; i++) 46 | { 47 | if(i < base * 2) 48 | ones[i] = ones[i%base]+1; 49 | else{ 50 | base *= 2; 51 | ones[i] = ones[i%base]+1; 52 | } 53 | } 54 | return ones; 55 | } 56 | }; 57 | ``` 58 | 59 | 60 | #更巧妙的代码 61 | 最高分代码:f[i] = f[i/2] + i%2 62 | 63 | 思想:和我的差不多,我是不看最高位,这个巧妙巧妙在不看最低位,直接右移1位,这个数在数组中肯定已经存在了,然后加上移走那位是0还是1(i%2 或者 i & 1) 64 | 65 | **其实整体思想都是把新的二进制模式映射到之前出现的二进制模式上去。** 66 | ```java 67 | public int[] countBits(int num) { 68 | int[] f = new int[num + 1]; 69 | for (int i=1; i<=num; i++) f[i] = f[i >> 1] + (i & 1); 70 | return f; 71 | } 72 | ``` 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /链表/024. Swap Nodes in Pairs My Submissions[E].md: -------------------------------------------------------------------------------- 1 | 024. Swap Nodes in Pairs[E] 2 | --- 3 | #题目 4 | Given a linked list, swap every two adjacent nodes and return its head. 5 | 6 | For example, 7 | Given 1->2->3->4, you should return the list as 2->1->4->3. 8 | 9 | Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed. 10 | 11 | 12 | #思路 13 | 这个题目的意思是每2个元素要交换一下,我们已经做了很多有关链表的问题,知道凡是涉及链表的操作,比较麻烦的地方都在与链表的操作都必须涉及到它的父亲。 14 | 15 | 这题也不例外,需要考虑很多问题: 16 | 1. 如果链表头要交换怎么办 17 | 2. 如何方便的交换两个节点 18 | 3. 如果长度不为偶数怎么办 19 | 20 | 21 | 问题1我们已经说过很多遍了,直接用一个新节点去解决这个问题。 22 | 23 | ListNode newhead = new ListNode(0); 24 | 25 | 问题2,这里得知道,如果涉及到链表交换操作,那么它至少涉及3个节点:当前节点,当前节点的父亲,当前节点的孩子这里由于我们循环是从前往后走的,所以我们这里使用:当前节点,当前节点的孩子,当前节点的孙子,可能更方便。 26 | 27 | ListNode first = current.next; 28 | ListNode second = current.next.next; 29 | 30 | 交换操作就很简单了 31 | 32 | first.next = second.next; 33 | current.next = second; 34 | current.next.next = first; 35 | current = current.next.next; 36 | 37 | 问题3,我们得需要加入判断,当前节点的孩子和孙子都要有才能继续 38 | 39 | while (current.next != null && current.next.next != null) 40 | 41 | 42 | 43 | 所以这样一分析,代码就很容易写出来了 44 | 45 | #代码 46 | ```java 47 | public class Solution { 48 | public ListNode swapPairs(ListNode head) { 49 | if(head == null) 50 | return null; 51 | ListNode newhead = new ListNode(0); 52 | newhead.next = head; 53 | ListNode current = newhead; 54 | while (current.next != null && current.next.next != null) { 55 | ListNode first = current.next; 56 | ListNode second = current.next.next; 57 | first.next = second.next; 58 | current.next = second; 59 | current.next.next = first; 60 | current = current.next.next; 61 | } 62 | return newhead.next; 63 | } 64 | } 65 | ``` 66 | 67 | -------------------------------------------------------------------------------- /查表/012. Integer to Roman[M].md: -------------------------------------------------------------------------------- 1 | 012. Integer to Roman[M] 2 | --- 3 | #问题 4 | Given an integer, convert it to a roman numeral. 5 | 6 | Input is guaranteed to be within the range from 1 to 3999. 7 | 8 | #思路 9 | 分析罗马数字的规律: 10 | 11 | |Symbol |Value| 12 | |-|-| 13 | |I | 1| 14 | |V | 5 15 | |X |10 16 | |L |50 17 | |C | 100 18 | |D| 500 19 | |M| 1,000 20 | 21 | 上面是罗马数字所有的符号。 22 | 罗马数字的规则: 23 | 一般情况下,从左到右从大到小排,字母代表的数字累加。 24 | 比如: 25 | >XII = 12 26 | > 27 | >MDCCLXVI= 1000+500+100+100+50+10+5+1 28 | 29 | 但是有特殊情况,就是,如果数字的范围在大数减小数的范围内,则会出现小数在大数前面的情况,代表(大数-小数) 30 | >IV = 5-1 31 | IX= 10 - 1 = 9 32 | XL = 50-10 = 40 33 | 34 | |Symbol |Value| 35 | |-|-| 36 | |IV | 4| 37 | |IX | 9 38 | |XL |40 39 | |XC |90 40 | |CD | 400 41 | |CM| 900 42 | 43 | 44 | ##思路1——循环 45 | 一旦把所有可能的情况符号情况都列举出来了,就好做了。 46 | 我们现在拿到一个数N 47 | 48 | 1. 我们就去表里面找不超过它的最大的数x, 49 | 2. 然后把它入我们的输出字符串中,然后将数N-=x, 50 | 3. 继续执行这个操作,直到N=0 51 | 52 | ```java 53 | public class Solution { 54 | public String intToRoman(int num) { 55 | int list[] = {1000,900,500,400,100,90,50,40,10,9,5,4,1}; 56 | String chars[] = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"}; 57 | int i = 0; 58 | String out=""; 59 | while(num > 0) 60 | { 61 | for(;i < list.length;i++) 62 | if(num >= list[i]) 63 | break; 64 | out+=chars[i]; 65 | num -= list[i]; 66 | } 67 | return out; 68 | } 69 | } 70 | ``` 71 | 72 | 73 | ##思路2——查表 74 | 还有个更极端的方案,就是,把每位上可能出现的情况都列举出来,剩下的,只用查表就行了。 75 | 76 | 77 | ```java 78 | public class Solution { 79 | public static String intToRoman(int num) { 80 | String M[] = {"", "M", "MM", "MMM"}; 81 | String C[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; 82 | String X[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; 83 | String I[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; 84 | return M[num/1000] + C[(num%1000)/100] + X[(num%100)/10] + I[num%10]; 85 | } 86 | } 87 | 88 | ``` 89 | 90 | -------------------------------------------------------------------------------- /链表/019. Remove Nth Node From End of List.md: -------------------------------------------------------------------------------- 1 | 19. Remove Nth Node From End of List 2 | --- 3 | #问题 4 | Given a linked list, remove the nth node from the end of list and return its head. 5 | 6 | For example, 7 | 8 | >Given linked list: 1->2->3->4->5, and n = 2. 9 | 10 | >After removing the second node from the end, the linked list becomes 1->2->3->5. 11 | 12 | #思路 13 | 这是链表中非常常见的问题,众所周知,链表慢就慢在遍历查找,而对于单链表来说,每次必须从头开始搜索,这样使得链表在处理“倒数”这个概念的时候,特别无力。常规的做法必须要2遍遍历:1遍计算链表长度len,1遍搜索倒数的元素len-n。(当然,你可以通过加入链表长度变量或者使用双向链表解决这个问题。) 14 | 15 | 但是题目要求是一遍完成,有没有一遍的思路呢?其实是有的,那就是双指针或递归。 16 | 17 | ##思路一 ——双指针 18 | 19 | 20 | 21 | 这里有个常用的做法去解决“倒数问题”:双指针。 22 | 23 | 双指针常用做法是: 24 | - 一个指针用来作为参考,控制长度(作为循环停止条件) 25 | - 一个指针延迟启动用来跑“倒数”。 26 | 27 | 第一个指针先运行n个数,然后打开第二个指针,这样,当第一个指针跑完时,第二个指针刚好跑过Len-N数,这样就找到了倒数第n个数。 28 | 29 | 注意:由于删除操作比较特殊,必须找到前一个节点才能删除下个节点,所以一般删除操作我们会构造一个虚拟节点作为开头,以防开头节点被删除。 30 | 31 | ``` 32 | public class Solution { 33 | public ListNode removeNthFromEnd(ListNode head, int n) { 34 | ListNode newhead = new ListNode(-1); //防止头被删除 35 | newhead.next = head; 36 | ListNode point1 = newhead; 37 | ListNode point2 = newhead; 38 | for(;point1 != null;point1 = point1.next,n--) //point1 控制长度 39 | { 40 | if(n < 0) 41 | point2 = point2.next; //point2延迟启动 42 | } 43 | point2.next = point2.next.next; 44 | return newhead.next; 45 | } 46 | } 47 | ``` 48 | 49 | 50 | ##思路二 —— 递归 51 | 除了用双指针外,还可以考虑用递归,凡是这种涉及单链表插入删除操作的时候,都可以考虑用递归,因为插入和删除都需要涉及它的父亲操作。我们考虑最后一个元素是第一层,然后逐级返回,当返回到第N+1层(也就是父亲节点所在层数)就开始删除操作。 52 | 53 | ``` 54 | public class Solution { 55 | public ListNode removeNthFromEnd(ListNode head, int n) { 56 | ListNode newhead = new ListNode(-1); 57 | newhead.next = head; 58 | remove(newhead,n); 59 | return newhead.next; 60 | } 61 | 62 | private int remove(ListNode node, int n) { 63 | if(node.next == null) return 1; 64 | int level = remove(node.next,n)+1; //层数+1 65 | if(level == n+1) //找到了父亲 66 | node.next = node.next.next; 67 | return level; 68 | } 69 | } 70 | ``` 71 | 72 | -------------------------------------------------------------------------------- /数学/007.Reverse Integer[E].md: -------------------------------------------------------------------------------- 1 | 007. Reverse Integer[E]——处理溢出的技巧 2 | --- 3 | 4 | #**题目** 5 | Reverse digits of an integer. 6 | 7 | Example1: x = 123, return 321 8 | Example2: x = -123, return -321 9 | 10 | #**思路** 11 | 这题完全没丝毫的难度,任何人几分钟都可以写出来,但是,这题修改后,加入了一个新的测试,瞬间大家讨论的就多了,就是——溢出测试 12 | 13 | 因为整数只有32位,可能原数不会溢出,但是转置后就不一定了,所以必须要考虑溢出的情况。 14 | 15 | #**思路1——用long** 16 | 一个比较讨巧的方案,直接用long不会溢出再和INT_MAX比较就好了 17 | ```c++ 18 | class Solution { 19 | public: 20 | int reverse(int x) { 21 | long tmp=0; 22 | while(x != 0) 23 | { 24 | tmp *=10; 25 | tmp += x%10; 26 | if(tmp > INT_MAX || tmp < INT_MIN) 27 | return 0; 28 | x /= 10; 29 | } 30 | return tmp; 31 | } 32 | }; 33 | ``` 34 | 35 | #**思路2——变化前后对比** 36 | bitzhuwei的代码。 37 | 不用任何flag和INT_MAX宏或者任何硬编码Ox7fffffff 38 | 这个思路 也是很容易理解的,做一些操作,如果溢出了,那溢出后的值做反向操作会和之前的值不一样。 39 | >这里就用一个变量存储变化后的值,每次做反向操作,如果和之前的值一样就更新,不一样,说明溢出了。 40 | ```c++ 41 | public int reverse(int x) 42 | { 43 | int result = 0; 44 | 45 | while (x != 0) 46 | { 47 | int tail = x % 10; 48 | int newResult = result * 10 + tail; 49 | if ((newResult - tail) / 10 != result) 50 | { return 0; } 51 | result = newResult; 52 | x = x / 10; 53 | } 54 | 55 | return result; 56 | } 57 | ``` 58 | 59 | ###**思路3——提前停止操作** 60 | 如果当前的数已经>INT_MAX/10 那么再做一次操作,必然溢出。 61 | ```c++ 62 | class Solution 63 | { 64 | public: 65 | int reverse(int n) 66 | { 67 | int result = 0; 68 | 69 | while (n != 0) 70 | { 71 | if (result > INT_MAX / 10 72 | || ((result == INT_MAX / 10) && (n % 10 > INT_MAX % 10))) 73 | { 74 | result = 0; 75 | break; 76 | } 77 | if (result < INT_MIN / 10 78 | || ((result == INT_MIN/ 10) && (n % 10 < INT_MIN % 10))) 79 | { 80 | result = 0; 81 | break; 82 | } 83 | result = result * 10 + n % 10; 84 | n = n / 10; 85 | } 86 | 87 | 88 | return result; 89 | } 90 | }; 91 | ``` 92 | 93 | -------------------------------------------------------------------------------- /字符串/003. Longest Substring Without Repeating Characters[M]/003. Longest Substring Without Repeating Characters[M].md: -------------------------------------------------------------------------------- 1 | 003. Longest Substring Without Repeating Characters[M] 2 | --- 3 | #题目: 4 | Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1. 5 | 6 | #分析 7 | 题目意思是在一个字符串中找一个最长的子串(没有重复的字母) 8 | 在简单的思路: 9 | 从左往右扩展子串,维持2个变量i和j来维持一个新的子串,j不断移动,每加入一个新的字符,判断是否有重复的,如果有重复的,移动i,生成新子串…… 10 | ``` 11 | len = max(len,j-i+1); 12 | ``` 13 | ![Alt text](./1459857033836.png)![Alt text](./1459857050765.png) 14 | ![Alt text](./1459857109997.png)![Alt text](./1459857137766.png) 15 | ![Alt text](./1459857157171.png) 16 | 17 | 18 | 19 | 这里有个问题就是,如何判断子串中是否有重复的字符,传统思路就是循环,这样每次查找重复的时间复杂度为O(n),导致整体时间复杂度为O(N^2),其实我们可以使用hashmap来存,这样可以保证每次查找的效率为O(1)。 20 | 21 | #代码 22 | ```c++ 23 | class Solution { 24 | public: 25 | int lengthOfLongestSubstring(string s) { 26 | unordered_map mymap; 27 | unordered_map::iterator it; 28 | int len = 0,i = -1; 29 | for(int j=0;j < s.length();j++) 30 | { 31 | /***是否有重复******/ 32 | it = mymap.find(s.at(j)); 33 | if(it != mymap.end()) 34 | /*****有重复的时候,移动i*****/ 35 | i = std::max(it->second,i); 36 | /****把新的字符加入*******/ 37 | mymap[s.at(j)] = j; 38 | len = std::max(len,(j-i)); 39 | } 40 | return len; 41 | } 42 | }; 43 | ``` 44 | 45 | 但是实际上,对于这个题目,不需要用hashmap,因为所有的字符ASCII码加起来也就最多255个,可以直接用数组来代替hashmap,效率更高。 46 | 47 | ```c++ 48 | class Solution { 49 | public: 50 | int lengthOfLongestSubstring(string s) { 51 | vector mymap(255,-1); 52 | int len = 0,i = -1,tmp; 53 | for(int j=0;j < s.length();j++) 54 | { 55 | tmp = mymap[s.at(j)]; 56 | i = std::max(tmp,i); 57 | mymap[s.at(j)] = j; 58 | len = std::max(len,(j-i)); 59 | } 60 | return len; 61 | } 62 | }; 63 | ``` 64 | 上面用了一个trick就是每个数组的初始化为-1表示没有出现重复,它不可能比i的初始值大,如果有重复的,直接覆盖,这样可以不用额外的语句判断是否出现重复。 65 | 66 | -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1460723068367.png: -------------------------------------------------------------------------------- 1 | �PNG 2 |  3 | 4 | IHDR{�ʿ�� IDATx��{�$G}����{sg��ٗ�qF�M��� AƀADۋ��VPP�FDBD7#!"�D@ND�L�sӇ�`�X���ľxz�s�����}罽}�v��������������;�տ���Tկ~]U]e������!�4[�A���KX��:uIY�P�I] @���s�7�$ e�DA@@WP���� 5 |   �j� �A@t$``6�Z��F��|�O 6 | �����J�����\�G�$A@@[P��f" ����YA@�%e�m�!�  �N�^�$A@@[P��f" ����YA@�%e�m�!�  �N�^�$A@@[P��f" ����Y�Pҡr� �(R�Yz�=�n���vR��0q �P��s!�NYI�5B���$$e�X?� 7 | ɶGL*�iD@:Kʾ�<;�I�U 5��T�C�D0 ����&��L�P�qRy��! �({���$SX��O*�.�@t"eߧ�eU\r� 8 | Y��Yr�*��t�'���s�LEÛ�ij��2&9e6��V��4ee��ŐԈ���Z,ɕ�S����Q��U�R��3+({�|��.� ��I�*�!��ޖ�� ʽ�+�R�9+({����&l�S�VE��eQ��=fS]T��u>�`��TwVP��y 9 | IMx�.U�<���Ȫߛ��w�=X�E�����w3J_�g,Xe���z>B2�g2���N��J�k?�R�>$A@76M�U�5�R��Rz���W�aHjC@�ʘ^�R��7+t���4$� �\!�R54��> 10 | 3z�V�Tv&�`��QV���s�p�eo��Y�juI>6� ��"X�s�+X��� 11 | I 12 | L:�TJ��U���i 13 | �Ե(��:�,���W�oHj@@i�`�KH 14 | ��(��:�,���W�oHj@�_��)�K&4GZ�m2a��U�|;WW`���Y`e��ߐԁ�Ui|9+{p�K� 15 | �b|���J�Dg���zvCR��v�6�uq\��ֈ�$m��&X�՝f���5$u" ����p��1^3w��V�3$&A�X��t�o���6a� }@ʾ2Q�n���6a� }@ʾ2Q�n���6a� }@��V�n�Q�"��ݘq�$�8�&��j ���J��'V`�N@]RV�Ѝ���  �-({m�uP���  ����6�qP'e�� 16 | �  �-({m�uP���  ����6�qP'e�� 17 | �  �-({m�u=T���F���R�}B�AGq;��R�y9s�E2��d�%�I�锩ڇ��M�r�`��I����z���� 18 | כI*/���6MK�VS�$u!�(�HF�32�H����'��WWV�+{m��l�����st�]RR&���tOP��Ϝ|�]l���k���j���f�D�,m ��� �ԳEgV=T�& 19 | �@jz=��z��)�Y����R�\�J{���z&��X;e*�nn]��[DsU�zC�����<(~�J=5g�Ce/gjz-����5��$}��U]�����yh�����7�A��Ro�r~�{��-JM7ug����h�d 20 | ���m�ER�����eQ������M�S��C���X����>��u�96��u����>��y��jH=�+�}��`� 21 | Em��T>4�sH��G6+nӢV���"�"�m�n Z� 22 | �� V�Y�V}b٫3�$��t��BAIw���&'shڃUlQj��VP�M9����ǀa��-��� V������z�AR��aOf�A 23 | R��(��:�,���W�oH��������:D@� @٫��$�hK�^۬C�e��e�/V�A� 24 | �T(y2Y`e��ߐh����w�;�F������;A1�ah[9 �7�޶��}�t���I�ӖM����?r��?���K��7A��B����& (�n��4l�+�9N��v�Z'e�-L���U�.�ل�eV��ũ�t��w�'/�y�޸�Kt�ޒ~V~X�����P��&�yx�WN�ƅ�w��-}�#N��Y��9��� 25 | �ل�=V���n���� 26 | -------------------------------------------------------------------------------- /动态规划/174. Dungeon Game[H]/174. Dungeon Game[H].md: -------------------------------------------------------------------------------- 1 | 174. Dungeon Game[H] 2 | --- 3 | # 问题 4 | he demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess. 5 | 6 | The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately. 7 | 8 | Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers). 9 | 10 | In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step. 11 | 12 | 13 | Write a function to determine the knight's minimum initial health so that he is able to rescue the princess. 14 | 15 | For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path `RIGHT-> RIGHT -> DOWN -> DOWN`. 16 | 17 | 18 | ![Alt text](./1473822748993.png) 19 | 20 | Notes: 21 | 22 | - The knight's health has no upper bound. 23 | 24 | - Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned. 25 | 26 | 27 | # 思路 28 | 29 | 这道题和《064.Minimum Path Sum》很相似,这里粗看是求线路上负值最小,但是仔细一想,这里有个问题,如果血量低于0,就是会立刻死去,所以这里其实是要找到一条线路,线路上任意时刻的累计负值最小。所以这里需要存到每个点的时候的线路上出现过的负值最大值。而为了方便计算后续的负值,还需要加上一个到当前的时候的值 30 | 31 | 设:R(i,j)表示走到i,j余留的值 32 | D(i,j)表示走到i,j 最大伤害量(最大负值) 33 | G(i,j):表示i.j格子内值 34 | 35 | 每到一个新的点,我们要判断是从上走下来需要的血多,还是从左边走过来需要的血多: 36 | remain_up = R(i-1,j) + G(i,j) 37 | remain_left = R(i,j-1) + G(i,j) 38 | damage_up = Min(up, D(i-1,j)) //这里用最小值是看是不是超过了原线路上的最小值 39 | damage_left = Min(left,D(i,j-1)) 40 | 41 | 我们看到底是从左边还是上边走下来需要的血量更多 42 | if(damage_up < damage_left) //说明从左边过来需要血量小 43 | { 44 | R(i,j) = remain_left; 45 | D(i,j) = damage_left; 46 | } 47 | else{ 48 | R(i,j) = remain_up; 49 | D(i,j) = damage_up; 50 | } 51 | 52 | 如果最后伤害大于0,那么返回1,否则返回伤害的绝对值+1 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /动态规划/064. Minimum Path Sum[M].md: -------------------------------------------------------------------------------- 1 | 064. Minimum Path Sum[M] 2 | --- 3 | 4 | ## 题目 5 | > Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. 6 | Note: You can only move either down or right at any point in time. 7 | 8 | 9 | 10 | 11 | ## 思路 12 | 13 | ### DP 14 | 这应该是很容易想到的,因为每次只能往下或右走,所以对于每个格,就两种可能: 15 | - 从上面走下来 16 | - 从左边走过来 17 | 那么很容易写出表达式:dp(i,j) = min(dp(i-1,j) , dp(i,j-1)) + path(i,j) 18 | 然后要做一个处理,就是对于第0行,和第0列只能从左边或上面走。这样判断很麻烦,其实有一个很简单的办法: 19 | 增加一行和一列,让这一行和这一列都为一个很大的值,这样,不管是第0行还是0列,都可以用统一的算法。 20 | (这里有个小注意点,就是我对minpath[0][1]赋值为0,这是为了更改原来minpath[0][0]位置的值) 21 | ```java 22 | public class Solution { 23 | public int minPathSum(int[][] grid) { 24 | int m = grid.length; 25 | if(0 == m) 26 | return 0; 27 | int n = grid[0].length; 28 | int [][] minpath = new int[m+1][n+1]; 29 | //init 0th row and 0th column to Max 30 | for(int i = 0;i <= m;i ++) 31 | minpath[i][0] = Integer.MAX_VALUE; 32 | for(int j = 0;j <= n;j ++) 33 | minpath[0][j] = Integer.MAX_VALUE; 34 | 35 | minpath[0][1] = 0; 36 | 37 | for(int i = 1;i <= m;i ++) 38 | for(int j = 1;j <= n;j++) 39 | minpath[i][j] = Math.min(minpath[i-1][j],minpath[i][j-1]) + grid[i-1][j-1]; 40 | 41 | return minpath[m][n]; 42 | 43 | } 44 | } 45 | ``` 46 | 47 | 48 | ### 一维数组 49 | 当然,上面的算法还可以改进,就是把二维数组换成一维数组,因为我们实际运行的时候发现,我们每次计算只和当前行的grid和之前行的minpath有关。 50 | 这个一维数组一直会更新,而更新条件就是 : dp[j] = min(dp(j),dp(j-1)) + grid(i,j) 51 | 这里同样为了避免第0列出问题(j-1越界),加入了1格,实际j从1开始 52 | 53 | ```java 54 | public class Solution { 55 | public int minPathSum(int[][] grid) { 56 | int m = grid.length; 57 | if(0 == m) 58 | return 0; 59 | int n = grid[0].length; 60 | int [] minpath = new int[n+1]; 61 | for(int i = 0;i <= n;i ++) 62 | minpath[i] = Integer.MAX_VALUE; 63 | 64 | minpath[1] = 0; 65 | 66 | for(int i = 0;i < m;i ++) 67 | for(int j = 1;j <= n;j++) 68 | minpath[j] = Math.min(minpath[j-1],minpath[j]) + grid[i][j-1]; 69 | 70 | return minpath[n]; 71 | 72 | } 73 | } 74 | 75 | ``` 76 | -------------------------------------------------------------------------------- /二分查找/033. Search in Rotated Sorted Array[H].md: -------------------------------------------------------------------------------- 1 | # 问题 2 | 3 | Suppose a sorted array is rotated at some pivot unknown to you beforehand. 4 | 5 | (i.e., `0 1 2 4 5 6 7` might become `4 5 6 7 0 1 2`). 6 | 7 | You are given a target value to search. If found in the array return its index, otherwise return -1. 8 | 9 | You may assume no duplicate exists in the array. 10 | 11 | 12 | 13 | # 思路 14 | 15 | 这个问题是二分查找的变种,它这里唯一的一个小trick就是把本来有序的数组做了一个旋转。但是注意,旋转的2部分是分别有序的。 16 | 17 | 18 | 19 | 还有一个很重要的特点:**后半部分小于前半部分**,所以其实很容易判断出**mid在哪一部分**。 20 | 21 | (如果num[mid] > num[0],我们就知道mid在左部分,否则在右部分。) 22 | 23 | 24 | 25 | 这里不能直接用二分的问题在于:**如果target和mid不在同一部,就会出错。** 26 | 27 | 28 | 29 | > 举例nums: [4,5,6,1,2,3,4],st = 0 , ed = 6,mid = 3, target = 6 30 | 31 | 此时:mid指向1,而target是6,说明mid和target不在同一部,会出现什么问题呢? 32 | 33 | 按照算法: 34 | 35 | ```java 36 | if (nums[mid] < target) 37 | st = mid+1 38 | ``` 39 | 40 | 这里,**明明应该往左搜索,但是却往右边搜索了**。 所以,为了解决这个问题。我们可以引入`inf`和`-inf` 41 | 42 | ## 引入inf和-inf 43 | 44 | 为了更加方便理解,我们举例: 45 | 46 | 我们随便看一个数组num:[4,5,6,1,2,3,4] 47 | 48 | - 假设我们查询的目标是3:那我们实际查询的是`右一段`:[4,5,6,**1,2,3,4**],实际上我们可以把前面的数都看作`-inf`:[-inf,-inf,-inf,**1,2,3,4**] 49 | - 假设我们查询的目标是5:那我们实际查询的是`左一段`:[**4,5,6,7,**1,2,3,4],实际上我们可以把后面的数都看作`inf`:[**4,5,6**,inf,inf,inf,inf] 50 | 51 | **这样其实就和普通的二分一样了。** 52 | 53 | 54 | 55 | ### 如何知道在哪一段? 56 | 57 | 1. 如果`target < nums[0]`和`nums[mid] target) 83 | ed = mid; 84 | else 85 | return mid; 86 | } 87 | return nums[st] == target?st:-1; 88 | } 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /数组/016. 3Sum Closest [M]/16. 3Sum Closest [M].md: -------------------------------------------------------------------------------- 1 | 16. 3Sum Closest [M] 2 | --- 3 | 4 | Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution. 5 | 6 | > For example, given array S = {-1 2 1 -4}, and target = 1. 7 | > The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). 8 | 9 | #思路 10 | 11 | >这个问题等于是3SUM又升级了,因为这里现在是最接近的结果,所以Hashmap的思路基本没用了,因为必须得要循环找到所有可能。当然,这个题目有个限制就是只有唯一的结果,所以,如果发现完全相等的,也就可以停下来了。 12 | 13 | 但是解题思路还是可以参考3SUM,算法基本一样,有些地方需要修改一下。首先,因为是找最接近的,所以要考虑所有情况,left循环到length-2 14 | 15 | for (int left = 0; left < nums.length-2; left++) 16 | 17 | 然后还是mid和right分别从两端往中央扫描,如果mid+right还比较小,那就需要mid右移,反之right左移(每次如果有最小的就存下来) 18 |
![Alt text](./1460991088774.png) 19 | 20 | 我们可以写出如下的代码: 21 | ```java 22 | mid = left+1; right = nums.length-1; 23 | while(mid < right) 24 | { 25 | int tmp = target-nums[left]; 26 | if(abs(tmp - nums[mid] + nums[right]) < abs(target-Min)) 27 | Min = nums[left] + nums[mid] + nums[right]); 28 | if(nums[mid] + nums[right] == tmp) 29 | return Min; 30 | else if(nums[mid] + nums[right] < tmp) 31 | mid++; 32 | else 33 | right--; 34 | } 35 | ``` 36 | 37 | 38 | #代码 39 | 40 | 41 | ```java 42 | public class Solution { 43 | public int threeSumClosest(int[] nums, int target) { 44 | Arrays.sort(nums); 45 | int mid,right; 46 | if(nums.length < 3) 47 | return 0; 48 | int Min = nums[0]+nums[1]+nums[2]; 49 | //left要循环全部 50 | for (int left = 0; left < nums.length-2; left++) { 51 | mid = left+1; right = nums.length-1; 52 | int tmp = target-nums[left]; 53 | while(mid < right) 54 | { 55 | if(Math.abs(tmp - nums[mid] - nums[right]) = lists.length) break; 45 | lists[i] = mergeTwoLists(lists[i],lists[i+step]); 46 | } 47 | ``` 48 | 49 | 所以代码涉及2层循环,外面是控制每隔多少合并一次,里面是遍历所有可以合并的链表,进行合并操作。 50 | 51 | 52 | ```java 53 | public ListNode mergeKLists(ListNode[] lists) { 54 | if(lists.length == 0) 55 | return null; 56 | //控制每隔多少 57 | for(int step = 1;step < lists.length;step*=2) 58 | //遍历所有可以合并的选项 59 | for(int i = 0;i < lists.length;i+=step*2) 60 | { 61 | //如果某个元素没有下一个元素就退出循环 62 | if(i+step >= lists.length) break; 63 | lists[i] = mergeTwoLists(lists[i],lists[i+step]); 64 | } 65 | return lists[0]; 66 | } 67 | //完全是之前的代码 68 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 69 | ListNode result = new ListNode(0); 70 | ListNode tmp = result; 71 | while(l1 != null || l2 != null) 72 | { 73 | if(l2 == null || (l1 != null && l1.val <= l2.val)) 74 | { 75 | tmp.next = l1; 76 | l1 = l1.next; 77 | } 78 | else 79 | { 80 | tmp.next = l2; 81 | l2 = l2.next; 82 | } 83 | tmp = tmp.next; 84 | } 85 | return result.next; 86 | } 87 | 88 | ``` 89 | -------------------------------------------------------------------------------- /二分查找/034. Search for a Range[M].md: -------------------------------------------------------------------------------- 1 | # 问题 2 | Given a sorted array of integers, find the starting and ending position of a given target value. 3 | Your algorithm's runtime complexity must be in the order of O(log n). 4 | If the target is not found in the array, return [-1, -1]. 5 | 6 | >For example, 7 | Given [5, 7, 7, 8, 8, 10] and target value 8, 8 | return [3, 4]. 9 | 10 | # 思路 11 | 题目里给了提示要求时间上必须是O(logN),那么暗示了这要用二分去做。 12 | 范围搜索也就是要确定一个上确界,一个下确界。 13 | 14 | 分别都可以用二分去找。 15 | ## 左边界 16 | 17 | 二分的话主要有以下几种情况,我们定义成3个基本规则: 18 | >Rule 1. A[mid] < target ,这时候说明还可以向右,st = mid+1 19 | Rule 2. A[mid] > target , 这时候说明应该在左边,ed = mid-1 20 | Rule 3. A[mid] == target ,这时候既可以左移,也可以不移动,ed = mid 21 | 22 | 因为作为二分,最后肯定是在2个数中选一个然后停止循环(while(st < ed))。 23 | 考虑下面几种情况,假设 target=5:(在两个数的情况下mid = st) 24 | ``` 25 | case 1: [3 5] (A[st] = target > A[ed]) 26 | case 2: [5 7] (A[st] = target < A[ed]) 27 | case 3: [5 5] (A[st] = target = A[ed]) 28 | case 4: [3 7] (A[st] < target < A[ed]) 29 | case 5: [3 4] (A[st] < A[ed] < target) 30 | case 6: [6 7] (target < A[st] < A[ed]) 31 | ``` 32 | 情况3就是Rule1的情况,`st = mid + 1`就行。 33 | 对于情况2-3这时候,我们只要 `ed = mid`就行了,其实也就是把Rule 2 和Rule 3合并成了 34 | > Rule 2*. A[mid] >= target, ed = mid 35 | 36 | 所以case 1-3 最后停止条件都是A[st] = A[ed] = target 37 | 38 | 对于case 4-6 都是A[st] != target,可以直接退出 39 | 40 | ## 右边界 41 | 找到了左边的边界后就好办了,右边的边界只用同理操作就行了。 42 | 而且因为找到了左边的边界,实际上就不存在比target小的数了。 43 | 44 | 这里,我们让mid偏向右边 45 | ``` 46 | mid = (st + ed)/2 + 1; 47 | ``` 48 | 然后主要控制ed移动就可以了。 49 | 50 | # 代码 51 | 52 | ```java 53 | public class Solution { 54 | public int[] searchRange(int[] nums, int target) { 55 | int [] result = new int [2]; 56 | result[0] = result[1] = -1; 57 | if(nums.length == 0) 58 | return result; 59 | 60 | int st = 0, ed = nums.length-1,mid; 61 | while(st < ed) { 62 | // 寻找左边界 63 | mid = (st + ed) / 2; 64 | if (nums[mid] < target) //保证st不会越过任何等于target的数 65 | { 66 | st = mid+1; //如果当前的数小于我们需要查的数,继续逼近 67 | } else { //如果大于等于 68 | ed = mid; 69 | } 70 | } 71 | if(nums[st] != target) 72 | return result; 73 | result[0] = st; 74 | // 寻找右边界 75 | ed = nums.length-1; 76 | while(st < ed) 77 | { 78 | mid = (st + ed)/2 + 1; //这里用+1是为了让mid偏向右边 79 | if(nums[mid] > target) 80 | { 81 | ed = mid-1; 82 | } 83 | else{ //因为st已经确定了,所以这里实际上不会出现比target小的数了,这里实际就是A[mid] == target 84 | st = mid; 85 | } 86 | } 87 | result[1] = ed; 88 | return result; 89 | } 90 | } 91 | ``` -------------------------------------------------------------------------------- /数学/029. Divide Two Integers[M].md: -------------------------------------------------------------------------------- 1 | 029. Divide Two Integers[M] 2 | ---- 3 | # 问题 4 | 5 | Divide two integers without using multiplication, division and mod operator. 6 | 7 | If it is overflow, return MAX_INT. 8 | 9 | # 思路 10 | 这道题难在不能使用乘除取余操作,所以我们只能手动的实现除法,我们来看看如何实现。 11 | 12 | 我们假设被除数为`D`,除数为`d` 13 | 14 | ## 手动实现除法 15 | 首先,本能想到10 = 2*5 ,10/2 = 5,说明10中有5个2,这里可以用循环来做,看`D`中间有多少个`d`就行了。 16 | 17 | 本能写出一个循环应该不难。 18 | ```java 19 | for(i = 0;dividend - divisor >= 0 ;i+=1) 20 | { 21 | dividend = dividend - divisor; 22 | } 23 | 24 | ``` 25 | 26 | ## 符号 27 | 现在有另一个问题,正负数怎么办?我们知道,除法里,异号为负,同号为正,既然不能使用乘除判断,那我们就只能写个判断,这个flag到时候就充当标志。 28 | 29 | ``` 30 | boolean flag = (dividend > 0 && divisor < 0 || dividend < 0 && divisor > 0); 31 | ``` 32 | 当然还有更好的实现方式,既然不能用乘除,可以用位运算呀,这和异或操作的含义刚好一样。 33 | ``` 34 | boolean sign = ((dividend < 0) ^ (divisor < 0)); 35 | ``` 36 | 然后,把`D`和`d`同时取绝对值就好了。 37 | ``` 38 | long did = Math.abs((long)dividend); 39 | long dis = Math.abs((long)divisor); 40 | ``` 41 | **注意:**这里除数一定要用long,因为如果最小值取绝对值会溢出 42 | 43 | ## 溢出 44 | 45 | 我们知道,除法可能产生溢出的情况就是`D`为0,或者`D`为`最小值`,`d`为-1 46 | 47 | ``` 48 | if (!divisor || (dividend == Integer.MIN_VALUE && divisor == -1)) 49 | return Integer.MAX_VALUE; 50 | ``` 51 | 52 | ## 更快的方案 53 | 好了,我们可以测试下代码。发现超时,想想也是,上面的循环太慢了。其实我们稍微想一下就可以提速,我们可以采用逐渐逼近的思路: 54 | - 我们先看i = N个`d`可不可以 55 | - 如果可以,我们看看i = 2N个`d`可以不可以 56 | - 如果还可以就继续看i = 4N个`d`可以不可以 57 | - 直到不可以减,我们让`D`减去i个`d` 58 | 59 | 这里为什么使用2的倍数,因为可以用位运算呀~~ 60 | 61 | d << 1 就相当与d*2 62 | d << 2 就相当与d*4 63 | 64 | 我们再用一个i来就记数 i = 0 开始 65 | 66 | 1 << 0 就相当于1 67 | 1 << 1 就相当于2 68 | 1 << 2 就相当与4 69 | 70 | 这里我们用一个临时变量`mul_d`存`d`的左移操作,**注意:**`mul_d`必须为long,因为左移操作很可能溢出!! 71 | 72 | 现在我们可以写出以下代码了。 73 | ```java 74 | public class Solution { 75 | public int divide(int dividend, int divisor) { 76 | if(divisor == 0 || (dividend == Integer.MIN_VALUE && divisor == -1)) 77 | return Integer.MAX_VALUE; 78 | int i,total = 0; 79 | //判断正负号 80 | boolean sign = ((dividend < 0) ^ (divisor < 0)); 81 | //这里必须要long,因为如果最小值取绝对值会溢出 82 | long did = Math.abs((long)dividend); 83 | long dis = Math.abs((long)divisor); 84 | while(did >= dis) 85 | { 86 | long mul_dis = dis; 87 | i = 0; 88 | //每次左移乘2,记录下来,直到不能减 89 | while(did >= (mul_dis<<1)) 90 | { 91 | i++; 92 | mul_dis <<= 1; 93 | } 94 | did -= mul_dis; 95 | total += 1< [] //1不取,2不取 47 | 48 | - 01 ——> [1] //取1 49 | 50 | - 10 ——> [2] //取2 51 | 52 | - 11 ——> [1,2] //取1,2 53 | 54 | 刚好可以取尽所有元素。 55 | 56 | 57 | 58 | 这个算法的复杂度是O(N^2),一层循环从0到2^n种取法,二层循环看每个取法对应的2进制中的1的个数 59 | 60 | 61 | 62 | ### 代码 63 | 64 | ```java 65 | 66 | public class Solution { 67 | 68 | public List> subsets(int[] nums) { 69 | 70 | List> mylist = new ArrayList>(); 71 | 72 | int len = 1< tmplist = new ArrayList(); 81 | 82 | for(int j = 0;j < nums.length;j++) 83 | 84 | { 85 | 86 | if(((1<> subsets(int[] nums) { 123 | 124 | List> mylist = new ArrayList>(); 125 | 126 | getsubset(mylist,0,nums,new ArrayList()); 127 | 128 | return mylist; 129 | 130 | } 131 | 132 | private void getsubset(List> mylist, int cur, int[] nums, List tmplist){ 133 | 134 | mylist.add(tmplist); 135 | 136 | for(;cur < nums.length;cur++) { 137 | 138 | List newlist = new ArrayList(tmplist); 139 | 140 | newlist.add(nums[cur]); 141 | 142 | getsubset(mylist, cur + 1,nums,newlist); 143 | 144 | } 145 | 146 | } 147 | 148 | } 149 | 150 | ``` 151 | 152 | -------------------------------------------------------------------------------- /动态规划/22. Generate Parentheses[M]/22. Generate Parentheses[M].md: -------------------------------------------------------------------------------- 1 | 22. Generate Parentheses[M] 2 | -- 3 | #问题 4 | 5 | Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. 6 | 7 | >For example, given n = 3, a solution set is: 8 | 9 | >"((()))", "(()())", "(())()", "()(())", "()()()" 10 | 11 | #思路1——DP 12 | 设:P[i]表示当n=i的时候括号组合串。 13 | 观察规律:我们知道,要形成一个括号的组合,肯定不是凭空产生的,产生一个P[3]的组合,那肯定是把"("和")"分别插在P[2]中间的。 14 | 15 | ![Alt text](./1462892959966.png) 16 | 17 | 18 | 我们假设产生P[3]组合的时候,之前的组合都是正确的,那么通过插入"(",")"肯定会把P[2]分成两个部分(括号内一个,括号外一个) 19 | 20 | 看似好像有很多插入的方法,但是,其实仔细想想,反正"("得增加一个,由于括号组合的第一一定是"(",为什么不把新增的"("放在开头呢?这样我们就只用考虑")"了 21 | 22 | 会怎么把P[2]切割就好了,我们知道P[2]的组合有P[0]+P[2],P[1]+P[1],P[2]+P[0], 23 | 24 | ![Alt text](./1462893036822.png) 25 | 26 | 27 | 通过写出前几个可以观察到下面的规律 28 | P[0]= [""] 29 | P[1] = [()] = "("+P[0]+")"+P[0] 30 | P[2] = [()(),(())] = "("+P[0]+")"+P[1] , "("+P[1]+")" +P[0] 31 | P[3] = [()()(),()(()),(())(),(()()),((()))] = "("+P[0]+")"+P[2] , "("+P[1]+")"+P[1], "("+P[2]+")" +P[0] 32 | 33 | 我们可以知道了组合方式: 34 | - P[i] = "("+P[i-j-1]+")"+P[j] ($j \in [0,n-1]$) 35 | 36 | 37 | 38 | ```java 39 | 40 | public class Solution { 41 | public List generateParenthesis(int n) { 42 | List> result = new ArrayList>(); 43 | //初始化P[0] = "" 44 | result.add((List)Arrays.asList(new String []{""})); 45 | for(int i=1;i <= n;i++) 46 | { 47 | result.add(new ArrayList<>()); 48 | for(int j = 0; j < i;j++) 49 | { 50 | //获取P[k] 51 | for (String s1 : result.get(j)) { 52 | //获取P[i-j-1] 53 | for(String s2 : result.get(i-j-1)) 54 | { 55 | result.get(i).add("(" + s1 + ")" + s2); 56 | } 57 | } 58 | } 59 | } 60 | return result.get(n); 61 | } 62 | } 63 | ``` 64 | 65 | 66 | #思路2:回溯 67 | 假设我能枚举所有的情况,我们考虑合理的括号组合是什么样的: 68 | 1. 左括号数==右括号数 69 | 2. 左括号一定要先于右括号 70 | 71 | 所以我们可以用一个大数组来表示字符串,2个指针left,right来表示左右括号,我们递归遍历所有情况,把满足条件的情况加入list就行了。 72 | 73 | 74 | ``` 75 | public class Solution { 76 | public List generateParenthesis(int n) { 77 | LinkedList result = new LinkedList(); 78 | if(n== 0) return result; 79 | backtracing(result,0,0,"",n); 80 | return result; 81 | } 82 | void backtracing(LinkedList result, int left, int right, String par, int max) 83 | { 84 | if(par.length() == 2*max) 85 | { 86 | result.add(par); 87 | return; 88 | } 89 | if(left < max) 90 | backtracing(result,left+1,right,par+'(',max); 91 | if(right < left) 92 | backtracing(result,left,right+1,par+')',max); 93 | } 94 | 95 | } 96 | ``` 97 | 98 | -------------------------------------------------------------------------------- /数学/008.String to Integer —atoi[E].md: -------------------------------------------------------------------------------- 1 | #008. String to Integer (atoi) [E] 2 | --- 3 | [TOC] 4 | ##**题目** 5 | Implement atoi to convert a string to an integer. 6 | 7 | Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases. 8 | 9 | Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front. 10 | 11 | ##**思路** 12 | 这题也比较好做,关键是要考虑挺多东西,我也是提交了好多次才发现有这么多要考虑的地方。 13 | 14 | - 开头的空格 15 | - 正负符号的处理 16 | - 溢出处理 17 | - 非法输入 18 | 19 | 20 | 21 | 开头空格处理: 22 | 23 | while(str[i] == " ") i++; 24 | 25 | 正负号的处理:我觉得yuruofeifei这个解决方案简直赞 26 | 27 | if (str[i] == '-' || str[i] == '+') { 28 | sign = 1 - 2 * (str[i++] == '-'); 29 | } 30 | …… 31 | return base * sign; 32 | 33 | 溢出处理(可以参考上一道题): 34 | 35 | if (base > INT_MAX / 10 || (base == INT_MAX / 10 && str[i] - '0' > INT_MAX%10)) { 36 | if (sign == 1) return INT_MAX; 37 | else return INT_MIN; 38 | } 39 | 40 | 非法输入:其实只用过滤就行了 41 | 42 | while (str[i] >= '0' && str[i] <= '9') { 43 | …… 44 | } 45 | 46 | ##**代码** 47 | 48 | 我的代码,不够简洁,可以参考yuruofeifei的代码,在下面 49 | ```c++ 50 | class Solution { 51 | public: 52 | int myAtoi(string str) { 53 | long tmp=0; 54 | bool neg; 55 | int i = 0; 56 | while(str[i] == ' ') i++; //读掉空格 57 | neg = str[i] == '-'?1:0; 58 | for(i = i+ (neg || str[i] == '+');i < str.length();i++) //如果是- 或 + i+1跳过符号 59 | { 60 | if(str[i] - '0' >= 0 && str[i] - '0' < 10) //过滤非法输入 61 | { 62 | tmp *= 10; 63 | tmp += (str[i] - '0'); 64 | if(tmp >= INT_MAX && !neg) //溢出判断 65 | { 66 | tmp = INT_MAX; 67 | break; 68 | } 69 | if(tmp -1 >= INT_MAX && neg) //除了符号,INT_MAX和INT_MIN只差1 70 | { 71 | tmp = INT_MIN; 72 | break; 73 | } 74 | } 75 | else break; 76 | } 77 | if(neg) return -tmp; 78 | return tmp; 79 | } 80 | }; 81 | ``` 82 | 83 | 84 | 85 | yuruofeifei的代码 86 | ```c++ 87 | int myAtoi(string str) { 88 | int sign = 1, base = 0, i = 0; 89 | while (str[i] == ' ') { i++; } 90 | if (str[i] == '-' || str[i] == '+') { 91 | sign = 1 - 2 * (str[i++] == '-'); 92 | } 93 | while (str[i] >= '0' && str[i] <= '9') { 94 | if (base > INT_MAX / 10 || (base == INT_MAX / 10 && str[i] - '0' > 7)) { 95 | if (sign == 1) return INT_MAX; 96 | else return INT_MIN; 97 | } 98 | base = 10 * base + (str[i++] - '0'); 99 | } 100 | return base * sign; 101 | } 102 | ``` 103 | 104 | -------------------------------------------------------------------------------- /topic_include.md: -------------------------------------------------------------------------------- 1 | # 目前收录的题目 2 | 3 | 为什么开这样一页,是因为分类的情况下,大家找题目可能不方便,为了方便大家找题目开了这一页,所有题目按顺序排列,大家可以用ctrl+f找自己需要的题目 4 | 5 | * [001. Two Sum[E]](数组/001.Two Sum[E].md) 6 | * [002. Add Two Numbers [M]](链表/002. Add Two Numbers [M].md) 7 | * [003. Longest Substring Without Repeating Characters[M].](字符串/003. Longest Substring Without Repeating Characters[M]/003. Longest Substring Without Repeating Characters[M].md) 8 | * [004. Median of Two Sorted Arrays[H]](分治/004. Median of Two Sorted Arrays[H]/004. Median of Two Sorted Arrays[H].md) 9 | * [005. Longest Palindromic [M]](字符串/005. Longest Palindromic [M].md) 10 | * [006. ZigZag Conversion[E]](规律/006.ZigZag Conversion[E].md) 11 | * [007. Reverse Integer[E]](数学/007.Reverse Integer[E].md) 12 | * [008. String to Integer (atoi) [E]](数学/008.String to Integer —atoi[E].md) 13 | * [009. Palindrome Number[E]](数组/009. Palindrome Number[E].md) 14 | * [010. Regular Expression Matching[[H]](动态规划/010. Regular Expression Matching/010. Regular Expression Matching.md) 15 | * [011. Container With Most Water[M]](数组/011. Container With Most Water[M].md) 16 | * [012. Integer to Roman[M]](查表/012. Integer to Roman[M].md) 17 | * [013. Roman to Integer[E]](查表/013. Roman to Integer[E].md) 18 | * [014. Longest Common Prefix[E]](字符串/014. Longest Common Prefix[E].md) 19 | * [015. 3Sum[M]](数组/015. 3Sum/015. 3Sum.md) 20 | * [016. 3Sum Closest [M]](数组/016. 3Sum Closest [M]/16. 3Sum Closest [M].md) 21 | * [017. Letter Combinations of a Phone Number[M]](数组/017. Letter Combinations of a Phone Number[M]/017. Letter Combinations of a Phone Number[M].md) 22 | * [018. 4Sum[M]](数组/018. 4Sum[M].md) 23 | * [019. Remove Nth Node From End of List[E]](链表/019. Remove Nth Node From End of List.md) 24 | * [020. Valid Parentheses[E]](数组/20. Valid Parentheses.md) 25 | * [021. Merge Two Sorted Lists[E]](链表/21. Merge Two Sorted Lists.md) 26 | * [022. Generate Parentheses[M]](动态规划/22. Generate Parentheses[M]/22. Generate Parentheses[M].md) 27 | * [023. Merge k Sorted Lists [H]](链表/023. Merge k Sorted Lists [H]/023. Merge k Sorted Lists [H].md) 28 | * [024. Swap Nodes in Pairs[E]](链表/024. Swap Nodes in Pairs My Submissions[E].md) 29 | * [026. Remove Duplicates from Sorted Array[E]](数组/026. Remove Duplicates from Sorted Array[E]/026. Remove Duplicates from Sorted Array[E].md) 30 | * [027. Remove Element[E]](数组/027. Remove Element[E].md) 31 | * [028. Implement strStr()[E]](数组/028. Implement strStr.md) 32 | * [029. Divide Two Integers[M]](数学/029. Divide Two Integers[M].md) 33 | * [033. Search in Rotated Sorted Array[H]](二分查找/033. Search in Rotated Sorted Array[H].md) 34 | * [034. Search for a Range[M]](二分查找/034. Search for a Range[M].md) 35 | * [035. Search Insert Position[M]](二分查找/035. Search Insert Position[M],md) 36 | * [064. Minimum Path Sum[M]](动态规划/064. Minimum Path Sum[M].md) 37 | * [120. Triangle[M]](动态规划/120. Triangle[M].md) 38 | * [292. Nim Game[E]](规律/292. Nim Game[E].md) 39 | * [338. Counting Bits [M]](动态规划/338. Counting Bits [M].md) 40 | * [374. Guess Number Higher or Lower[E]](二分查找/374. Guess Number Higher or Lower[E].md) 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /规律/006.ZigZag Conversion[E].md: -------------------------------------------------------------------------------- 1 | 006.ZigZag Conversion[E] 2 | --- 3 | #题目 4 | The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) 5 | 6 | ![Alt text](./1460215156918.png) 7 | 8 | And then read line by line: "PAHNAPLSIIGYIR" 9 | Write the code that will take a string and make this conversion given a number of rows: 10 | 11 | >string convert(string text, int nRows); 12 | 13 | convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR". 14 | 15 | ##思路1——用字符串数组 16 | 我能说我一开始完全没看懂吗?我是根据**Custom Testcase**自己慢慢测试摸索出来的。 17 | 其实,应该是这样的 18 | 2行: 19 | A _ C _ E _ 20 | _ B _ D _ F 21 | 22 | 3行: 23 | A _ _ _ E _ _ _ I _ _ _ 24 | _ B _ D _ F _ H _ J _ 25 | _ _ C _ _ _ G _ _ _ K 26 | 27 | 所以有个简单的思路: 28 | - 每行弄个string。 29 | - 对原始字符串进行扫描,从上往下,从下往上,依次加入每行的string 30 | - 最后把所有的string拼接起来 31 | ```c++ 32 | class Solution { 33 | public: 34 | string convert(string s, int numRows) { 35 | string str[numRows],tmp; 36 | if(numRows == 1) 37 | return s; 38 | int flag; 39 | for(int i = 0,j = 0;i < s.length(); i++) 40 | { 41 | if(j == 0) 42 | flag = 1; 43 | if(j == numRows-1) 44 | flag = -1; 45 | str[j] += s[i]; 46 | j += flag; 47 | } 48 | for(int i = 0; i < numRows;i++){ 49 | tmp += str[i]; 50 | } 51 | return tmp; 52 | } 53 | }; 54 | ``` 55 | 56 | ##思路2——观察规律 57 | 58 | 2行: 59 | A _ C _ E _ 60 | _ B _ D _ F 61 | 62 | 3行: 63 | A _ _ _ E _ _ _ I _ _ _ 64 | _ B _ D _ F _ H _ J _ 65 | _ _ C_ _ _ G _ _ _ K 66 | 67 | 4行: 68 | A _ _ _ _ _ G _ _ _ _ _ 69 | _ B _ _ _ F _ H _ _ _ 70 | _ _ C _ E _ _ _ I _ K 71 | _ _ _ D _ _ _ _ _ J 72 | 73 | 74 | 观察规律后,以每行的元素作为轴,可以发现,下面的字母都是对称排列的 75 | 换成对应的index后,规律更明显 76 | 0 _ _ _ 4 _ _ _ 8 _ _ _ 77 | _ 1 _ 3 _ 5 _ 7 _ 9 _ 78 | _ _ 2 _ _ _ 6 _ _ _ 10 79 | 80 | 第2层的元素就是以第一行的元素为轴,+1,-1 81 | 第三层的元素就是以第一行的元素为轴,+2,-2 82 | …… 83 | 但是最后一层的元素,由于其特殊性,我们可以只考虑+k 84 | 85 | Ps.所有过界的元素都不考虑 86 | 87 | 轴也有规律:除了首尾两层,其他都是2个,所以第一层每隔**2n-2**出现一次。 88 | 89 | 90 | ```c++ 91 | class Solution { 92 | public: 93 | string convert(string s, int numRows) 94 | { 95 | string tmp; 96 | if(numRows == 1) 97 | return s; 98 | int inc = 2*numRows-2; //每次轴增加的步长 99 | int len = s.length(); 100 | for(int i = 0; i < numRows;i++) 101 | { 102 | for(int j = 0;j < s.length()+numRows; j += inc) 103 | { 104 | if(j - i > 0 && j - i < s.length() 105 | && i != 0 && i != numRows -1) //首,尾只考虑+不考虑- 106 | tmp+= s[j-i]; 107 | if(j + i < s.length()) 108 | tmp += s[j+i]; 109 | } 110 | } 111 | return tmp; 112 | } 113 | }; 114 | ``` 115 | -------------------------------------------------------------------------------- /数组/001.Two Sum[E].md: -------------------------------------------------------------------------------- 1 | 001.Two Sum[E] 2 | --- 3 | 4 | #1.题目 5 | 6 | Given an array of integers, return indices of the two numbers such that they add up to a specific target. 7 | 8 | You may assume that each input would have exactly one solution. 9 | 10 | Example: 11 | 12 | Given nums = [2, 7, 11, 15], target = 9, 13 | Because nums[0] + nums[1] = 2 + 7 = 9, 14 | return [0, 1]. 15 | 16 | #2.思路 17 | 作为我们可能进入leetcode遇到的第一题,大家对它可谓是又爱又恨,而且它确实又有很多解法,总结起来可以有以下3种,3种还都能A过.... 18 | 19 | 20 | ##2.1双重循环 21 | 最简单的思路,两重循环,没啥技术含量,速度很慢,毕竟是$O(N^2)$ 22 | ```c++ 23 | class Solution { 24 | public: 25 | vector twoSum(vector& nums, int target) { 26 | vector result; 27 | for(int i = 0;i < nums.size();i++) 28 | { 29 | for(int j = i+1;j < nums.size();j++) 30 | if(nums[i] + nums[j] == target) 31 | { 32 | result.push_back(i); 33 | result.push_back(j); 34 | return result; 35 | } 36 | 37 | } 38 | } 39 | }; 40 | ``` 41 | ##2.2 排序 42 | 其实简单的想,用一个排序都能把复杂度降到$O(NlogN)$,通过排序,然后用两个指针从前后扫描逼近真值(注意这个思想,可以让O(N*N)的复杂度降为O(N),充分利用排序,因为一定会有一个值满足,然后通过值去原数组里找对应的下标(这里其实就可以考虑,如果当初就用一个数据结构存好键值对应关系就好了,其实就是hashmap,下面的做法就用到了) 43 | (下面代码是 dugu9sword写的java代码,我就没写成c++的,主要看思路,还是比较好理解的) 44 | 45 | ```c++ 46 | public class Solution { 47 | public int[] twoSum(int[] nums, int target) { 48 | int[] nums_sorted=new int[nums.length]; 49 | System.arraycopy(nums,0,nums_sorted,0,nums.length); 50 | //Quicksort. 51 | Arrays.sort(nums_sorted); 52 | 53 | //Find the two numbers. O(n) 54 | int start=0; 55 | int end=nums_sorted.length; 56 | while(starttarget); 58 | if(nums_sorted[end]+nums_sorted[start]==target) 59 | break; 60 | while(nums_sorted[++start]+nums_sorted[end] twoSum(vector& nums, int target) { 85 | vector result; 86 | unordered_map mymap; 87 | int res; 88 | for(int i = 0;i < nums.size();i++) 89 | { 90 | res = target - nums[i]; 91 | unordered_map::iterator it = mymap.find(res); 92 | if(it != mymap.end()) 93 | { 94 | return vector({it->second,i}); 95 | } 96 | mymap[nums[i]] = i; 97 | } 98 | } 99 | }; 100 | ``` 101 | 102 | -------------------------------------------------------------------------------- /链表/002. Add Two Numbers [M].md: -------------------------------------------------------------------------------- 1 | 2.Add Two Numbers [M] 2 | --- 3 | # 题目: 4 | 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. 5 | 6 | Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) 7 | Output: 7 -> 0 -> 8 8 | 9 | #思路: 10 | 题目的大意是两个链表求和,和也是一个链表(链表是逆序存的数字) 11 | 这和大数的加减很像,不过这个进位是从后向前。 12 | 所以可以同时从前往后加,然后保留进位。 13 | 14 | 其实做这种大数加减的题目不管是用的大数组还是链表,都是一样的: 15 | 16 | - 首先做个大循环,对每一位进行操作: 17 | 18 | - 当前位:(A[i]+B[i])%10 19 | - 进位:(A[i]+B[i])/10 20 | 21 | 这里要注意一点,就是可能两个数组不是同样的长度,需要考虑一个数组已经到头,另一个数组还没结束的情况 22 | #代码 23 | 我的这个代码写的不够好,考虑的过于复杂,可以直接看下面更精巧的代码。 24 | ```c++ 25 | /** 26 | * Definition for singly-linked list-> 27 | * struct ListNode { 28 | * int val; 29 | * ListNode *next; 30 | * ListNode(int x) : val(x), next(NULL) {} 31 | * }; 32 | */ 33 | class Solution { 34 | public: 35 | ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { 36 | //异常判断 37 | if(l1 == NULL && l2 == NULL) 38 | return NULL; 39 | if(l1 == NULL) 40 | return l2; 41 | if(l2 == NULL) 42 | return l1; 43 | //初始化 44 | ListNode * result = new ListNode((l1->val + l2->val)%10); 45 | int carry = (l1->val + l2->val)/10; //表示进位 46 | ListNode* templ1 = l1; 47 | ListNode* templ2 = l2; 48 | ListNode* tempresult = result; 49 | //这里弄一个结束节点,有利于当一个节点到结尾后做操作 50 | ListNode* EndNode = new ListNode(0); 51 | while(templ1->next != NULL || templ2->next != NULL) 52 | { 53 | //如果某个链表已经到结尾了,那么就把它变成EndNode,特点是值为0,next = NULL 54 | if(templ1->next == NULL) 55 | templ1 = EndNode; 56 | else 57 | templ1 = templ1->next; 58 | if(templ2->next == NULL) 59 | templ2 = EndNode; 60 | else 61 | templ2 = templ2->next; 62 | tempresult->next = new ListNode((templ1->val + templ2->val + carry)%10); 63 | carry = (templ1->val + templ2->val + carry)/10; 64 | 65 | tempresult = tempresult->next; 66 | 67 | } 68 | if(carry == 1) 69 | tempresult->next = new ListNode(1); 70 | return result; 71 | 72 | } 73 | }; 74 | 75 | ``` 76 | 77 | #更精巧的代码 78 | 不得不说,potpie的这个代码比我上面的代码精简了不少,我上面的代码考虑的太多了,因为我通式用的templ1->val + templ2->val + carry,导致每次需要对先结束的链表进行尾部填充,而且开头多了很多额外的代码。 79 | 80 | 他的代码,2个链表是独立操作的,而且代码写的很精简,基本没废话!赞 81 | ```c++ 82 | public class Solution { 83 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 84 | ListNode c1 = l1; 85 | ListNode c2 = l2; 86 | ListNode sentinel = new ListNode(0); 87 | ListNode d = sentinel; 88 | int sum = 0; 89 | while (c1 != null || c2 != null) { 90 | sum /= 10; 91 | if (c1 != null) { 92 | sum += c1.val; 93 | c1 = c1.next; 94 | } 95 | if (c2 != null) { 96 | sum += c2.val; 97 | c2 = c2.next; 98 | } 99 | d.next = new ListNode(sum % 10); 100 | d = d.next; 101 | } 102 | if (sum / 10 == 1) 103 | d.next = new ListNode(1); 104 | return sentinel.next; 105 | } 106 | } 107 | ``` 108 | 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](146082043110733.png) 2 | 3 | By [Voidsky(黄锴)](https://github.com/hk029) 4 | 5 | --- 6 | # 写在前面 7 | >本人一直有写书的“小梦想”,机缘巧合碰到gitbook,也算看缘分,虽然我知道这本“书”远达不到想象中的书的概念,但是,我仍然视其我第一本书。尽管它不能出版,也不会被人广泛阅读,但却值得我小心呵护。我希望通过自己的努力能慢慢的让这本"不是书的书"变得丰满起来。也算是给我最后这段校园时光留下点什么印记。 8 | 9 | 2015-05-05: 10 | >今天,突然发现leetcode上我写的所有的中文思路贴都被删了,心情还是有些低落,我看见了站长对我的“善意提醒”,他说的也没错,毕竟是在别人的地盘。 11 | ![Alt text](./1462450627386.png) 12 | 13 | 14 | >不过,在短短几天,我看见了大家对我的支持,我很感动,也许没机会再在leetcode上用中文发思路了,但是我还是想坚持把这本书完成,虽然不一定会有很多人看了,怎么说呢,坚持吧! 15 | ![Alt text](./1462450863918.png) 16 | 17 | # LeetBook介绍 18 | 19 | >LeetBook电子书的地址:[https://www.gitbook.com/book/hk029/leetbook/details](https://www.gitbook.com/book/hk029/leetbook/details) 20 | 21 | LeetBook理论上不是一本书,它是我做leetcode已来的一些笔记,总结。 22 | 23 | 本“书”不是一蹴而就的,是本人在刷题过程中做的笔记逐步积累起来的,并会随着我的刷题而变得丰富。 24 | 25 | 每道题后面的[E][M][H]代表了这个题的难度等级,分别是轻松,略有难度,很难 26 | 27 | **强调:**本人并不是什么大神,只是喜欢整理归纳,喜欢把别人的思维转换成自己更易懂的形式。在刷题过程中,会有很多自己的解题思路和感想,也会有很多灵光一现的瞬间,我习惯用马克飞象(一个支持印象笔记的第三方markdown编辑器)把这些瞬间捕捉下来,所以我很多笔记都存在印象笔记中。而偶然间遇到gitbook,又刚好支持markdown,这也促成就是这本书的诞生。 28 | 29 | # LeetBook怎么看 30 | 这本“书”你可以横着看,竖着看,躺着看(开玩笑了),怎么看取决于你了,我讲讲我是怎么组织这本书的: 31 | - 我在第二页写了一个目录,包含了所有收录的题目,你可以从这里入手,查找你需要的题目找踢解 32 | - 我把题型分类了,我会**选择**一部分我觉得能学到点东西的题目放在这里面,你可以通过侧栏寻找感兴趣的。 33 | 34 | # 为什么要写做这个? 35 | 我相信很多为了找工作都开始刷LeetCode了,我也不例外,LeetCode目前应该是找工作领域最权威的刷题网站了,上面的题目都很有代表性,也是很多公司喜欢问的,所以也成就了现在刷LeetCode的狂热。 36 | 37 | 但是,很多人都发现了一个问题,只是一味的刷题,却没有机会对每个题目做一个整理或总结。导致题目做过一遍,但是没什么印象,很多题目虽然A过了,但是实际上用的是比较笨,或者比较费时的思路,有更多更精彩,更简单的思路没有考虑到。导致一遍下来收获并不大。 38 | 39 | 所以这里推出这本书,一方面,方便大家A题后来复习看看,也方便大家来这里找每道题新的思路。也督促自己对每道题尽可能的想全面点。 40 | 41 | 42 | # 这本书力求做到 43 | 1. 覆盖尽可能多的题目 44 | 2. 每道题力求多种思路解决 45 | 3. 解答思路尽可能清晰,易懂 46 | 47 | 这也算对自己的一个鞭策,每道题让自己考虑出更加容易理解的思路,也方便日后的复习。 48 | 49 | 50 | # 声明 51 | 1. 它不是一本算法或数据结构书,这毕竟是一本有关解题思路的“书”,它默认你是有一定的算法和数据结构基础的,如果你在这方面还十分欠缺,推荐你看下下面相关推荐的书(我以后有时间可能会结合自己的能力加上每类题型的讲解,相关算法等) 52 | 2. 关于语言,这里不推荐任何语言,我觉得语言只是工具,思路才是最重要的,所有的思路其实都可以快速的用特定的语言实现,大多就是语法上的细微区别,我觉得大家还是不要把注意力放在特定的实现上。我也不会在解题的时候拘泥于特定的语言,之前我大部分是使用c++,但是有些题目用python确实方便我也会用python,之后我A题主要使用java(考虑以后工作可能会用java), 53 | 2. 这本“书”目前是我一个人闲暇时间完成,所以更新速度上不会特别快,大概每周4-6篇,跟我这周做题时间有关。 54 | 55 | 56 | # 相关推荐 57 | - 书籍推荐(以下链接都是豆瓣读书的链接,可以方便你了解详情) 58 | 1. [《算法》](https://book.douban.com/subject/10432347/)(红宝书,书内有能运行的代码,大量图示,而且讲解的通俗易懂,作者是普林斯顿大学计算机学院院长,Kuth的徒弟,算法界的牛人!这里我不打算推荐算法导论,因为它太深了,不适合以找工作为目的的同学) 59 | 2. [《大话数据结构》](https://book.douban.com/subject/6424904/)(数据结构就推荐这本,国内教材都过于悔涩,这个适合自学) 60 | 3. [《编程珠玑》](https://book.douban.com/subject/3227098/)(你会很明确知道什么叫精华) 61 | 4. [《编程之美》](https://book.douban.com/subject/3004255/)(微软的面试宝典) 62 | 5. 待续 63 | - 博客推荐 64 | 1. [blog.csdn.net/hk221976](blog.csdn.net/hk221976) (不要脸的先推荐了自己的博客 -- 捂脸) 65 | 2. [http://www.nowamagic.net/](http://www.nowamagic.net/) 简明现代魔法原本是一个个人博客,现在已经发展成一个清新的、动漫风的、专注于将Web开发技术尽可能简明易懂地描述出来的IT社区,在这里你可以轻松愉快地学习Web开发技术。 66 | 67 | # 关于评论 68 | 目前已经加上了评论功能,可以在每一页的底部发现输入评论。可以用自己的社交账号登录,评论功能由多说提供支持。 69 | 70 | ![Alt text](./1461598844843.png) 71 | # 联系我 72 | 毕竟是自己一个人的工作,虽然每道题我都力求做到完善。但是可能还是会出现一些不足,如果有什么问题或建议,可以联系我: 73 | 74 | - 黄锴 75 | - 邮箱 [hk2291976@hotmail.com](hk2291976@hotmail.com) 76 | - 简书 [http://www.jianshu.com/users/30f737ee0051/latest_articles](http://www.jianshu.com/users/30f737ee0051/latest_articles) 77 | - 个人主页 [Voidsky](voidsky.cc) 78 | - CSDN博客 [blog.csdn.net/hk221976](blog.csdn.net/hk221976) 79 | - qq 263791865 80 | 81 | 82 | 83 | # 更新情况 84 | ## 1.2版本 85 | 86 | 1. 更新题目到30多道 87 | 2. 新增章节“双指针” 88 | 89 | ## 1.1版本 90 | 1. 加入katex,支持Latex算数表达式 91 | 92 | 2. 加入了多说评论插件,可以支持评论 93 | 94 | 3. 目前题目更新到21题 95 | 96 | ## 1.0版本 97 | 这是最原始的版本,完善了首页介绍和书的框架,加入了目前整理的解题思路 98 | -------------------------------------------------------------------------------- /数组/017. Letter Combinations of a Phone Number[M]/017. Letter Combinations of a Phone Number[M].md: -------------------------------------------------------------------------------- 1 | 017. Letter Combinations of a Phone Number[M] 2 | --- 3 | #问题 4 | Given a digit string, return all possible letter combinations that the number could represent. 5 | 6 | A mapping of digit to letters (just like on the telephone buttons) is given below. 7 | ![Alt text](./1461570562032.png) 8 | 9 | >Input:Digit string "23" 10 | Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 11 | 12 | #分析 13 | 14 | 这题其实含义是是枚举所有可能的组合方式。如果题目要求是枚举“23”的所有可能字母组合,我们很好做,2重循环对吧?但是现在难就难在,一开始你不知道输入是什么,你没办法确定组合长度,组合个数,也没办法确定循环层数,这时候怎么办??? 15 | 16 | 这里有两个思路,也是很常用的思路:递归,队列。 17 | #思路1:递归 18 | 递归一般是解决一些整体不好求的问题。它通过把大问题划小,然后找到一种特定的规律,然后求解。 19 | 20 | 递归的思路我们很好理解,我们没办法确定整体,我可以先从入手。 21 | 22 | 假定有个数字串“23456” 23 | 24 | - 假定除了数字'2'的组合已经求出来了,准备求'3',那我只要把‘3'所代表的'def'加到之前字符串他们每一个的后面就好。 25 | - 假定除了数字'2'的组合已经求出来了,准备求'4',那我只要把‘4'所代表的'hij'加到之前字符串他们每一个的后面就好。 26 | …… 27 | - 一直这样推下去,直到发现6'后面是空的了,那将当前这个字符串加入列表就好了。 28 | 29 | 30 | ```java 31 | 32 | public class Solution { 33 | private char[][] dict = { {},{ 'a', 'b', 'c' }, { 'd', 'e', 'f' }, { 'g', 'h', 'i' }, { 'j', 'k', 'l' }, { 'm', 'n', 'o' }, 34 | { 'p', 'q', 'r', 's' }, { 't', 'u', 'v' }, { 'w', 'x', 'y', 'z' } }; 35 | public List letterCombinations(String digits) { 36 | LinkedList result = new LinkedList(); 37 | if(digits.length() == 0) 38 | return result; 39 | addNumber(result,0,"",digits); 40 | return result; 41 | } 42 | public void addNumber(List list, int i, String curstr, String digits) 43 | { 44 | if (i == digits.length()) { 45 | list.add(curstr); 46 | return; 47 | } 48 | char[] candidates = dict[digits.charAt(i) - '1']; 49 | for (char c : candidates) 50 | addNumber(list, i+1, curstr + c, digits); 51 | } 52 | } 53 | ``` 54 | 55 | 56 | #思路2:用队列 57 | 队列的思路也不算太难理解。如果递归算纵向求解的话,队列就是横向求解。每加入一个新的数字的时候,就把当前队列的元素全都扩充一遍。使得队列不仅在长度上,也在宽度上增加了。这就像一个装配流水线。半成品每流过一个工人,工人就把之前的产品拿出来,往上安装一个零件,然后放到传送带上,让它继续传到下个工人那。 58 | 59 | 1. 一共需要的工人数,就是数字串长度,它决定了产品需要经过几道加工 60 | ``` 61 | for(int i = 0;i < digits.length(); i++) 62 | { 63 | } 64 | ``` 65 | 2. 然后我们看目前有多少个不同的半成品需要加工 66 | ``` 67 | int pos = digits.charAt(i) - '0'; 68 | int size = result.size(); 69 | for(int j = 0;j < size;j++) 70 | { 71 | } 72 | ``` 73 | 74 | 3. 然后就开始加工了,我们获取每个数字对应的字符串长度,这就是工人需要加工的零件个数。这里加工是把每个半成品拿出来,复制多份,然后按上新的零件 75 | ``` 76 | String tmp = result.remove(); 77 | for(int k = 0;k < map[pos].length();k++) 78 | result.add(tmp+map[pos].charAt(k)); 79 | ``` 80 | 81 | ##整体代码 82 | 83 | ```java 84 | public class Solution { 85 | public List letterCombinations(String digits) { 86 | LinkedList result = new LinkedList(); 87 | if(digits.length() == 0) 88 | return result; 89 | String[] map = new String[] {"0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; 90 | result.add(""); 91 | for(int i = 0;i < digits.length(); i++) 92 | { 93 | int pos = digits.charAt(i) - '0'; 94 | String s = map[pos]; 95 | int size = result.size(); 96 | for(int j = 0;j < size;j++) 97 | { 98 | String tmp = result.poll(); 99 | for(int k = 0;k < s.length();k++) 100 | result.add(tmp+s.charAt(k)); 101 | } 102 | } 103 | return result; 104 | } 105 | } 106 | ``` 107 | 108 | 这里,我用了size变量来存之前加工好的半成品个数(因为队列会在加工后扩充,size会变化), 109 | 110 | int size = result.size(); 111 | for(int j = 0;j < size;j++) 112 | 113 | 114 | 但是,高分答案中有个思路,我觉得很赞。(要是想不到这个,就用我上面的写就好了,多一行代码而已) 115 | 116 | while(ans.peek().length()==i) 117 | 118 | 这里ans.peek().length()是取出第一个元素的长度,当长度等于i的时候,说明是当前需要加工的半成品,而加工完后,队列中的每个元素长度都会增加1,所以,这时候循环就会停止。 119 | 120 | -------------------------------------------------------------------------------- /数组/015. 3Sum/015. 3Sum.md: -------------------------------------------------------------------------------- 1 | 015. 3Sum 2 | --- 3 | #问题 4 | Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. 5 | 6 | Note: 7 | Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c) 8 | The solution set must not contain duplicate triplets. 9 | For example, given array S = {-1 0 1 2 -1 -4}, 10 | 11 | A solution set is: 12 | (-1, 0, 1) 13 | (-1, -1, 2) 14 | 15 | #思路 16 | 17 | >这个问题其实就是2 SUM的变种问题,和这个问题类似的还有4SUM,解题思路也可以参考2SUM。我们知道2SUM还可以用暴力两重循环解决,3SUM如果暴力就要三重循环,想想也可怕。 18 | 19 | 考虑一下如何将3SUM问题转变一下:如果我们随机确定了一个数a,问题是不是就变成了,在剩下的数里面找到2个数和为0-a,是不是就和2SUM问题一样了? 20 | 21 | 其实这题相比2SUM多了几个难点: 22 | 23 | 1. 数组里允许重复的数 24 | 2. 结果要按升序排列 25 | 3. 结果中不能出现重复的结果 26 | 27 | 28 | 当然,我们可以通过写很多条判断语句解决这些问题,但是其实稍微想一下,可以发现,只要保证数组一开始就有序就好办很多了。 29 | 30 | 我们可以选择3个变量,left,mid,right。在循环的时候,永远保证相对顺序就行了。这样在插入结果的时候,就自然是升序的。 31 | 32 | 我们可以参考[2SUM的思路2]()解决这道题。 33 | 34 | 首先,我们考虑如何确定第一个数left,这肯定是我们第一层循环。第一个数可不能无限制的随便选,因为我们要保证上面的几个条件都满足,我们要保证它时刻是最小的数,那么我们可以考虑left取到全部非正数就行了。(如果要和为0,至少要有1个非正数) 35 | 36 | for (int left = 0; left < nums.length && nums[left] <= 0; left++) 37 | 38 | 然后就是mid和right的确定了,我们采用思路2的方案,mid和right分别从两端往中央扫描,如果mid+right还比较小,那就需要mid右移,反之right左移 39 |
![Alt text](./1460991088774.png) 40 | 41 | 我们可以写出如下的代码: 42 | ```java 43 | mid = left+1; right = nums.length-1; 44 | while(mid < right) 45 | { 46 | int tmp = 0-nums[left]; 47 | if(nums[mid] + nums[right] == tmp) 48 | addtolist; 49 | else if(nums[mid] + nums[right] < tmp) 50 | mid++; 51 | else 52 | right--; 53 | } 54 | ``` 55 | 56 | 一切看起来特别美好了,可以当你提交的时候,你会发现,还是会报错,因为它虽然能解决问题2,但是不能处理重复结果。举个最简单的例子: 57 | -2 -2 -1 -1 0 1 1 2 2 58 | 这个代码会输出数个[-2 0 2] [-1 0 1] ,解决方案也很简单,如果一个left指向的数是之前判断过的,跳过,如果mid和right往中间移动的时候,是刚才的数,也跳过。 59 | ```java 60 | mid = left+1; right = nums.length-1; 61 | while(mid < right) 62 | { 63 | int tmp = 0-nums[left]; 64 | //跳过left重复匹配 65 | if(left > 0 && nums[left] == nums[left-1]) 66 | continue; 67 | 68 | if(nums[mid] + nums[right] == tmp) 69 | { 70 | int tmp_mid = nums[mid],tmp_right= nums[right]; 71 | list.add(Arrays.asList(nums[left], nums[mid], nums[right])); 72 | //跳过right和mid的重复匹配 73 | while(mid < right && nums[++mid] == tmp_mid); 74 | while(mid < right && nums[--right] == tmp_right); 75 | } 76 | else if(nums[mid] + nums[right] < tmp) 77 | mid++; 78 | else 79 | right--; 80 | } 81 | ``` 82 | 83 | #代码 84 | 85 | 86 | ```java 87 | public class Solution { 88 | public List> threeSum(int[] nums) { 89 | Arrays.sort(nums); 90 | List> list; 91 | list = new ArrayList>(); 92 | int mid,right; 93 | //left只用循环所有的非正数就行了(不是负数是因为还要考虑[0 0 0]的情况所以是非正数) 94 | for (int left = 0; left < nums.length && nums[left] <= 0; left++) { 95 | mid = left+1; right = nums.length-1; 96 | int tmp = 0-nums[left]; 97 | //跳过left重复匹配 98 | if(left > 0 && nums[left] == nums[left-1]) 99 | continue; 100 | while(mid < right) 101 | { 102 | if(nums[mid] + nums[right] == tmp) 103 | { 104 | int tmp_mid = nums[mid],tmp_right= nums[right]; 105 | list.add(Arrays.asList(nums[left], nums[mid], nums[right])); 106 | //跳过right和mid的重复匹配 107 | while(mid < right && nums[++mid] == tmp_mid); 108 | while(mid < right && nums[--right] == tmp_right); 109 | } 110 | else if(nums[mid] + nums[right] < tmp) 111 | mid++; 112 | else 113 | right--; 114 | } 115 | } 116 | return list; 117 | } 118 | } 119 | ``` 120 | 121 | -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1460724147977.png: -------------------------------------------------------------------------------- 1 | �PNG 2 |  3 | 4 | IHDR����}� IDATx�� �%U�翬����~P��4z�y]`EGt{�uYft��K �(��8b��;F��5t]G�����}�V�Gc��ҡ,�ʶ�y��Y��B�H�]]]]�U����'+�޼7O�W��q#__��_~���u]���p�t]���X���+u꒨W�YM�?I(&ͶmX��,[� 5 | @@@���fR5RhvP��R`V��%Q��J�����Wh&UgI���2,h�"[  �� �YA@@��� Z�����:(CuV�(((Â,�  �N�P�$A@ 6 | Jʰ��l����2TgI���2,h�"[  �� �Y�QҡzU#M�R�ٌ֪�5�����vR��0q O��W���⟅D>@棜D*+ ��J*�#H*� ���Pq�'�J%ٺ�I�Ǔ � �!e����D�J�O+�������!��A��螆TNqRy��! #e���IV�j“ʫ� 9((Ì���p�ud�g4�umZ��2L* ���N���7�G���j��t ��D�D����@��:V��Sq9�����Y�eX��X�\�?_ՌVz�)�d���iX%�o�Ĵ'3��J��u�Ŵ��Ս�W���q 7 | e����j���N��v��im[���;��Uh~��7{\� 8 | �NIA���� �M�C�C��F���1階���ge8~��q�,�SqF#�I٠���lQKt�)�n�`��l�"G�ػ�-�Lэ��Y/���Uo��p���@�;|��k1�'Y� $ 9 | e8><�E^��K�ó3����f3������^��%���/������>�{�[V�[䇦N�Bh��OJ�qn�� K�� �p��A �;�z��U��n�|���χ�<BF*���e8�*�2��0#�d�C�q��D��X��H7�;��:�R:� *k˃�l��*^S�e� 10 | vD:ՂS*��ȡ��IU6c�a� �i���lR�0� qX[?�@ ��Ŏ��j�Vj� Ut� �^¥�_�宛v�Ԋ�4���kJD �FU�M���$�<5�C�Rþ�z��ך�dG��)DN�X%g�6���.���6�Ӑ�'|���f�S&TyA���\.�/���r~].25�D�U`���>g�,!�9������HE�����n3�"�0�U�o#�4p�����p�N���wȼ���0������Fطp?���}��酽���30��0�� 11 | ��$ �g��R�B�Yd�Y�����"X%/g�0H�m#h +�J�@e�%��6���i��=��1��S_O@�� 12 | e����=���N����ǃjJ�����W��� [T|Զb���I��t�n�H�����bED-���U+���h����e8~��q����Hm�~I] ���M��d���.Ģ��7z9�oi�� |O���Z�����Wm�)���2�?�'�m����V����ҙ!����}X�.�� �l�����eX�Y) �@@ 5P���G�  Y!e���@:@@R#e�zD   �P�Y) �@@ 5�m�nj�#b��u](C��p�t��Nw��D�*��� X��� V!=O��'��M� 13 | ͤ!,8(#(�2�:�   "e�2�2,c�#�  !P�!8(#(�2�:�   "e�2�2,c�#�  !P�!8(#(�2�:�   "0Fe�P����U��l����5�����vR��0�r�ԫ�����*K���өSU���3��X'I��d�� 14 | Xu#�y='�ƨ ;��JB�I��c��U�j�a�*����_|hUM���}��#Bb+I"~V���D�X�� %�J%����2���7_�:�v���ghD�gN��3.�?z�g���6�j�z��Q�2,X� X����N� 15 | �����K*�^H����A~���M�k�B���|f��T;u��fP�`p���Š/���>$�%�ODx�� � 16 | �j��0���i���W��G��K�I��� 17 | -س ���4���z|0�hiI�^^��zV��M� 18 | ��y�GV�+C��N��{� 19 | �L*x4��5��V�^n31��;�lr4:�1��ax�̎E�Q�cHm�Q��:�*:��*C�玲��htm�K*�^X�,,g�,Vl�Aq��� C4�:�ZX*��h.QW�*�J�����2�&�� 0DM�S�(Y�rtr�YB���+X���zC��d�SJ�0Y���:/��+(C�2�d8^�!��:�s���'�ԙ�U�YA��1$A@ 20 | Jʰ��l����2TgI���2,h��5[I.��/���%`U|VP��e\Hɕw��r��yC�@@@���*�ʭ��NZ�����m5Z;t�9����B�RZ֪�x� K�����YA���@�R�>+�Ԟ+�������I*�������:ջzY���Z���� T�bY��� 22 | �<Ȁ�z)����z�RR۶���ͤ��}�8V��@�Ln+uȬjTm׈V�4��ʽ��\�P�� cY����|���z9����z��*�ԫ�iZۯ�B'o�����+���J<��"-��Kr������`�J�1��� 23 | ɼ���+��'o���S2��8X 24 | ���< 25 | V�e�7VP��e[x�QY�G����$�<�����<6�b 0یX�B'�v�����b66H����j�yU|`�N6O�4�u]���W�q����b{���+� �}�O�d�#���⹇�߽�xPMp���٫n"VݶvVl 26 | >w˕D�⑝7�NS\����^��Y;�n�g�z��c4������u+�uUV����9�Rŝ)�w;,Cuf�����/��]��[����q���,�%-�:��@� @���߰�Ŷ��=D�"5k���֟:4`ʲ�����jӳ!v���p @�g!C��3y�y!���Ŵe3?��X�2�؃@� Ӡ��8�x�����(�u(�8���ڲ���+�e�n���@�lQ���a�pz��}4E�eF{1{�w?���l��d�=���f�6F�������X>zy1��U��ѻh������� ^O�.��6�fC��d��/������ț?Aks���E?臙d2��4�u�ͤ��R��I؃�(`j�"U9�VQ�C,oS+:2���x��ٕ������?�q3a��t�M�ͤ�M�|/����v�Ÿ'e&���ݠ�Aɰ {�R/e� 27 | ͤ�� م@\�X�z�3{�燴z�AZ������HflE�M�/l�]I�]%�A`�� GI�Da���g��s����{h�e��d6�i�_���t�̎������2;���V�~W�_�A`T� GE�����s��OŮ���u�� �:���֡ �D��CB�aI-k�{(�a�D8>8��c�]���:�Ђ�u����%5�A`x� ��!���x�^v��D٭C "����e-�a�!e8�� �^���[H��g�:<��.���r/f��V�aY��N ��'e8zƈ��θ��ї��nz`Y=��xyl�n̎��A:q�I��QS@`x� /(�T&�����,���lk��&mb i;v��瞧�%�����[:lNl���+?@ӕ7v�K�@�ӫ�r����#eB�3��Jlgƣt�{Xp-�z�[?�3<��&e�Wc���=�z��H�D�lGފ����m���ر;V�L�J<�Zc2���Y�e=��?�2U �uh� ���\M��RZٶ�䀎a��,֡��w��q:���)hYk[������U���2�g�= �NժIN[ʌ�K 28 | ����N��1�}�;t�7���i�l� 29 | =��3�{괈Y\�X����&wc�ܥ#�9�W�Fa:�*UM&fP�mИ0uͦ����h��T���@�J�㔞+u�9ae�^����jլ���=m�/{���� 30 | �t�q��t=p��P �9}�6N%��r�[��%amn<�䐚�,�i5ꂬ3ac��5�:K�jLE�w4`��.O�0�T�\S� V,�]7��M�ԏE�j��jL=�m �>���іW�B���$F�n���4������W�=���yiB�d��[��H��ٽ�����pR�� 31 | 8��co4����5�/�ļ� 5nc�0ɨ�"ի86��+u��c�bS"�K] 32 | �]��W�� 33 | �6]��%�]�kR�!d�5}�2��e5x"69�>,y�pSDӑ�~Y�?��?����k�]��G�S����O�����]���|�]���:⊼�z�%�"XEb���CVl]`S ��KK-!���+Br7_�]BiB�t���3�<:�˃�< 34 | ���������P��I�U�Y��T��OQҡf���ɘ��G�� 35 | q,Zla�b��A 36 | {��l<ޘ���zy�U�YeC�h#��w�~9��R� H:�d�b� 37 | �Ӆ���^���³JWZ��4�)FIn���j��^3�/�W*"R����8F�+�����JUZ�7��hش���mQKT�p�$�Ðt�Sr���"�+u�`U|V�*C9W�����E�&?��I�dRU�*I��_*���~d^�L��K��@@`�2� �d۴�ֹ�\y���WxI;�ѿ���M+��W������RvԝM'���I�"H�2 +BݴÎ�����k��_-ݛ_hYJ�/4o~a��1DW->H����z9�U�Y�� �z�{��&ٮKv�� 39 | u�E����z�I����4�͑�Eǃ��I�JX�Uj�PZ/�1�ӫ����^E��i^hC��z����� 飴�8��!@�R VEg��2T�2�{�Q/��J��F���N��^�,���܉ �AiQq _C"�z����*5e���2��+� ��5 /uY���gr[�CfU�j�F�j��l��h�Z%8�{@���'t�B8z�䑕� 40 | U×����:}Q?�v�\�/��j]�t��A�3��㘥���L㠬d8��mS��OQuL\�X��ߘ�?�6+�b�+I"~V���D�X�f�W�p�i°_R �����l3�������Eaõ�W1���*#�0O�4��1��mn�t�[K#���m�/�]���=C�Z�V����l..��?��p��S�tޙ[ivz2F^N���K�ǙN�R� 41 | V`�N@]R֫�'ݫ'8���.�����P����N��_�7p2���'����y:g�4��;.���� 42 | v����� �j3i�ˀ-A� 43 | y{�����ǎ 44 | ����zI(B��c������� @��_���Ch��iZ[�O������y�����mS(@@`����5�:���{��}����B���=y��x��F�}�9}���@@��2L�,���m���q���!+�$���u��O�����靈vN��8-��9�6����]{_9�ѳ'��V^��[_����������}���a���i��x�K[���3!�-Q�F_n���o�e��/8A��_���#�㲗Оsg7�ڜZd�p��o�'��?�]���]����(�U�4�$��:Z�+u꒲^��Pg�S����ă^�v�CO)� 45 | ʱ��<��P�{�(�!�z��������=C��<��7���Ǘ��S7A@FC�p�\y� ~���O����< 46 | �y 47 | -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/010. Regular Expression Matching.md: -------------------------------------------------------------------------------- 1 | 010. Regular Expression Matching 2 | --- 3 | 4 | @(leetcode解题思路)[DP] 5 | 6 | #**问题** 7 | Implement regular expression matching with support for '.' and '*'. 8 | 9 | >'.' Matches any single character. 10 | '*' Matches zero or more of the preceding element. 11 | 12 | >The matching should cover the entire input string (not partial). 13 | 14 | >The function prototype should be: 15 | bool isMatch(const char *s, const char *p) 16 | 17 | >Some examples: 18 | isMatch("aa","a") → false 19 | isMatch("aa","aa") → true 20 | isMatch("aaa","aa") → false 21 | isMatch("aa", "a*") → true 22 | isMatch("aa", ".*") → true 23 | isMatch("ab", ".*") → true 24 | isMatch("aab", "c*a*b") → true 25 | 26 | 27 | #思路 28 | 29 | 这里面最复杂的操作是"\*",这是个很可恶的操作,因为你永远不知道它多长。但是有一点,"\*"不会单独出现,它一定是和前面一个字母或"."配成一对。看成一对后"X*",它的性质就是:要不匹配0个,要不匹配连续的“X” 30 | 31 | 题目的关键就是如何把这一对放到适合的位置。 32 | 33 | 考虑一个特殊的问题: 34 | 情况1: 35 | “aaaaaaaaaaaaaaaa" 36 | "a*aa*" 37 | 38 | 情况2: 39 | “aaaaaaaaaaaaaaaa" 40 | "a*ab*" 41 | 42 | 在不知道后面的情况的时候,我如何匹配a*? 43 | - 最长匹配 44 | 显然不合适,这样后面的a就无法匹配上了 45 | 46 | - 匹配到和后面长度一样的位置,比如情况1,就是留3个a不匹配,让后面3个字母尝试去匹配。 47 | 这样看似合适,但是遇到情况2就不行了。 48 | - 回溯,每种"*"的情况我都匹配一次,看哪种情况能成功,如果其中出现了问题,马上回溯,换下一种情况 49 | 50 | 51 | 52 | ##思路1——回溯 53 | 如果“\*”不好判断,那我大不了就来个暴力的算法,把“*”的所有可能性都测试一遍看是否有满足的,用两个指针i,j来表明当前s和p的字符。 54 | 我们采用从后往前匹配,为什么这么匹配,因为如果我们从前往后匹配,每个字符我们都得判断是否后面跟着“*”,而且还要考虑越界的问题。但是从后往前没这个问题,一旦遇到“\*”,前面必然有个字符。 55 | 56 | - 如果j遇到"\*",我们判断s[i] 和 p[j-1]是否相同, 57 | - 如果相同我们可以先尝试匹配掉s的这个字符,i--,然后看之后能不能满足条件,满足条件,太棒了!我们就结束了,如果中间出现了一个不满足的情况,马上回溯到不匹配这个字符的状态。 58 | - 不管相同不相同,都不匹配s的这个字符,j-=2 (跳过“\*”前面的字符) 59 | ```c++ 60 | if(p[j-1] == '.' || p[j-1] == s[i]) 61 | if(myMatch(s,i-1,p,j)) 62 | return true; 63 | return myMatch(s,i,p,j-2); 64 | ``` 65 | - 如果j遇到的不是“*”,那么我们就直接看s[i]和p[j]是否相等,不相等就说明错了,返回。 66 | 67 | ```c++ 68 | if(p[j] == '.' || p[j] == s[i]) 69 | return myMatch(s,i-1,p,j-1); 70 | else return false; 71 | ``` 72 | - 再考虑退出的情况 73 | - 如果j已经<0了说明p已经匹配完了,这时候,如果s匹配完了,说明正确,如果s没匹配完,说明错误。 74 | - 如果i已经<0了说明s已经匹配完,这时候,s可以没匹配完,只要它还有"\*"存在,我们继续执行代码。 75 | 76 | 77 | 所以代码应该是这样的: 78 | 79 | ```c++ 80 | class Solution { 81 | public: 82 | static const int FRONT=-1; 83 | bool isMatch(string s, string p) { 84 | return myMatch(s,s.length()-1,p,p.length()-1); 85 | } 86 | bool myMatch(string s, int i, string p,int j) 87 | { 88 | if(j == FRONT) 89 | if(i == FRONT) return true; 90 | else return false; 91 | if(p[j] == '*') 92 | { 93 | if(i > FRONT && (p[j-1] == '.' || p[j-1] == s[i])) 94 | if(myMatch(s,i-1,p,j)) 95 | return true; 96 | return myMatch(s,i,p,j-2); 97 | } 98 | if(p[j] == '.' || p[j] == s[i]) 99 | return myMatch(s,i-1,p,j-1); 100 | return false; 101 | } 102 | }; 103 | 104 | ``` 105 | 106 | ##思路2——DP 107 | DP的话,肯定要用空间换时间了,这里用 monkeyGoCrazy 的思路:用2维布尔数组,dp[i][j]的含义是s[0-i] 与 s[0-j]是否匹配。 108 | 109 | >1. p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1] 110 | >2. If p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1]; 111 | >3. If p.charAt(j) == '*': here are two sub conditions: 112 | - if p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2] //in this case, a* only counts as empty 113 | - if p.charAt(j-1) == s.charAt(i) or p.charAt(i-1) == '.': 114 | dp[i][j] = dp[i-1][j] //in this case, a* counts as multiple a 115 | dp[i][j] = dp[i][j-1] // in this case, a* counts as single a 116 | dp[i][j] = dp[i][j-2] // in this case, a* counts as empty 117 | 118 | 119 | 这里用的bool数组比较巧妙,初始化为true。前两种情况好理解,如果匹配成功就维持之前的真假值。程序的目的是看真值能不能传递下去。如果遇到三种情况,我们就看哪种情况有真值可以传递,就继续传递下去。 120 | 121 | 122 | ##初始化 123 | ```c++ 124 | dp[0][0] = true; 125 | //初始化第0行,除了[0][0]全为false,毋庸置疑,因为空串p只能匹配空串,其他都无能匹配 126 | for (int i = 1; i <= m; i++) 127 | dp[i][0] = false; 128 | //初始化第0列,只有X*能匹配空串,如果有*,它的真值一定和p[0][j-2]的相同(略过它之前的符号) 129 | for (int j = 1; j <= n; j++) 130 | dp[0][j] = j > 1 && '*' == p[j - 1] && dp[0][j - 2]; 131 | ``` 132 | ##图示 133 | 我用excel自己跑了下代码,画了一下示意图,下面橘黄色表示正常匹配了,蓝色表示“\*”匹配空串。可以看出真值是如何传递下去的。 134 | 135 | 例1:"aaa" 和 正则式"aa" 136 | 137 | ![Alt text](./1461923981629.png) 138 | 139 | 140 | ![Alt text](./1461922697867.png) 141 | 142 | 143 | 例2:"aabc" 和 正则式"a\*bc" 144 | 145 | ![Alt text](./1461923916690.png) 146 | 147 | 148 | 149 | ![Alt text](./1461923856937.png) 150 | 151 | 152 | 153 | 例3:"aaaa" 和 正则式"a\*b\*" 154 | 155 | 156 | ![Alt text](./1461923613623.png) 157 | 158 | ![Alt text](./1461923701320.png) 159 | 160 | 161 | 162 | #代码执行 163 | ```c++ 164 | for(int i = 1;i <= n;i++) 165 | { 166 | for(int j = 1;j <= m;j++) 167 | { 168 | //这里j-1才是正常字符串中的字符位置 169 | //要不*当空,要不就只有当前字符匹配了*之前的字符,才有资格传递dp[i-1][j]真值 170 | if(p[j-1] == '*') 171 | dp[i][j] = dp[i][j-2] || (s[i-1] == p[j-2] || p[j-2] == '.') && dp[i-1][j]; 172 | else 173 | //只有当前字符完全匹配,才有资格传递dp[i-1][j-1] 真值 174 | dp[i][j] = (p[j-1] == '.' || s[i-1] == p[j-1]) && dp[i-1][j-1]; 175 | } 176 | } 177 | 178 | ``` 179 | 180 | ##返回值 181 | ```c++ 182 | return dp[n][m] 183 | ``` 184 | 185 | ##完整代码 186 | ```c++ 187 | class Solution 188 | { 189 | public: 190 | static const int FRONT=-1; 191 | bool isMatch(string s, string p) 192 | { 193 | int m = s.length(),n = p.length(); 194 | bool dp[m+1][n+1]; 195 | dp[0][0] = true; 196 | //初始化第0行,除了[0][0]全为false,毋庸置疑,因为空串p只能匹配空串,其他都无能匹配 197 | for (int i = 1; i <= m; i++) 198 | dp[i][0] = false; 199 | //初始化第0列,只有X*能匹配空串,如果有*,它的真值一定和p[0][j-2]的相同(略过它之前的符号) 200 | for (int j = 1; j <= n; j++) 201 | dp[0][j] = j > 1 && '*' == p[j - 1] && dp[0][j - 2]; 202 | 203 | for (int i = 1; i <= m; i++) 204 | { 205 | for (int j = 1; j <= n; j++) 206 | { 207 | //由于表格中是从1开始的,而字符串中是以0开始的,所以i-1和j-1才对应字符串中的字符。 208 | if (p[j - 1] == '*') 209 | { 210 | dp[i][j] = dp[i][j - 2] || (s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]; 211 | 212 | } 213 | else //只有当前字符完全匹配,才有资格传递dp[i-1][j-1] 真值 214 | { 215 | dp[i][j] = (p[j - 1] == '.' || s[i - 1] == p[j - 1]) && dp[i - 1][j - 1]; 216 | 217 | } 218 | } 219 | } 220 | return dp[m][n]; 221 | } 222 | }; 223 | ``` 224 | 225 | -------------------------------------------------------------------------------- /动态规划/010. Regular Expression Matching/1460724161261.png: -------------------------------------------------------------------------------- 1 | �PNG 2 |  3 | 4 | IHDR��%9>� IDATx�� �Wy��5��FOے,llYk,������m-����x1�ւMor���dC ;�a���aaE�%q�C�„5���`�~��!��m���h4����UwUW�TWߚ���ǿ��S�n}u��߽]�}~Wۼy�y�uׁG{�a@�����Y��"+u��,W��P��$@$@$���7lؐ��2�$@$@$�@`�Ȱ�P���B5L��t�a�Y�P�d����U��Q�H�H %�S��L& � ��:*GuV�$ H *ǔd4�I$@$�N��Q�%I�H�RB��1%�d� � ��rTgEI  ���rLIF3�$@$@���YQ�H�H %�S��L& � ��:*GuV=�4P�jд,�F�����iȺ=��A��a�E$@$�H�ʱ�G��2�� 5 | *y� � ���c ���L&ؾ�A�È3�$ ���r�lN��d$r������M8#F$@}'@���,��1� 6 | *�0I�H ��c��:t�U������R�H��I��1���+�0�r�8�J0� 7 | �<��ʻ�M��("�Ug��,_��-�5 8���0�R�EV�gE娞Ŕ�k�K������4���%*�蒕:X�J+*G�|�d����*>����ݿzk���#�����K6Y����zVS2F����˕���s(9��e�Dc���F���y�UzXQ9��5%cD�:�j��0`�N@�ڽ��t�>���\���ʟ��n�YQ9�s��T�� ��&+�R'�.�rE娞��L(�Ohʺ�,�RgJV�f�@=��$�8(#�qҍZΑ�'�"����rT�aJƊ?^��EVd�N@]2���ݪ�9M��h�S��J�R�ڲ�ֳub���#JV� �*M��rT�mJƄ�Q,V�.�T*c�0&���M�RgLV�bŖ�z~S2&ƍ�� =��W1�k�b��P�IV�X�*]������1!�4=ܱt�D�M�RKV�bE娞ߔ� {�.�����k��e3_Fζ�x;UWd���d�.VT���Mɸȕ�8�"t�ơi�”I:�����K5Y����zvS2F,�U��O쪚�x����u3�d�N���Ê�U����q#`�}��v�}Mܭv,��O��c���OЉ�ՎE��}–c���$@$@�$@��|a�H�H��H�ʱ���j  �h�r�f�0V$@$@}$@��G�|5 � �@4 h�7o67l���1V$@$@$��R]�if��a��THd��I�Ȋ�� �K�\uƊݪ��(I$@$�T�)�h&�H�H@���:+J� � ���cJ2��$ P'@��Ί�$@$@)!@嘒�f2I�H�� P9���$ � �@JP9�$��L  uT���(I$@$�T�)�h&�H�H@�@����bV��eQ4��,��OC��i�*_3-.����iZ��$:h:�"�Z��I9�y�K���2i�CV�����!�+ǹ��'жkPy���ݷ��T( 8 | �ZFܓB���W�/J�J+6v��I�?�U{F�D\YEB9�3�`Ѓ�������Q�Q����{�B��p�[��� �t�*TK[�l�Sy��HKV��BV�`�c��#���������O�jkQ>�z�Ӭ`,X}"�ɞO��"�V��T L��k�*f�baj��yQ�!+�L$�԰��r���W5��Mߠ�A��K/�b��P+��a�X�J� [|*9�jZ�\Lo둬|�R�M�j��{wV�P�U�:t�U���u3�����:s(U�j݁�MD"n`|\^�#��M�:��vKel���Al�� 9 | �R�OVib�s�X�i'˕Zv�W�d]�GCfk6��Bf���n_k�7o6����n���� À���)Ĕ�,�����kd��.lq%k'~��$�!㓣�}�H��V��������3�#K���֝��x׮ݻ�{�%F�aֲ� ���}�ħ�W��C(G+V���,��}_��K� �n�`%ˆ��q�/+�s�v��UP6�iL�����bŖcP�����.ؿ�����lEj�+����;i���{w'P�����R�؝CG�b��B����9�n���Q``�z��3@~�:����|�Y�Յ� VqeӜ�`���n\����W�"�����7 �����5�ʪ�"�X��}��r��z\���bp͙��; 11 | ��j �y�58�ҫ��(kP�V|�[�ʑA��(��CH�o�*l�������8\{�b�19�8v�9x�) 12 | ��#?��|�Z����@FF~�Z�3۷E%�ţ������QB��0��Z�� ^q����;��`����]��z��y'V�T���7����<�\��o�桽�?���Øz��0��X��֜�2m�'���������g1|��0�deK����,�Һ�� �=�0���p�џ`����~�����}��:�C{1��w�=�{��L/^��O?[)=��H#���`��W(=E�vl�ˎ��*il:�//VT��z ��5�h��]9J:������ ë׵���~��m�b��D�&�o��߹]�bh�y�Va$�rъϢ���*_����ܜ�+1 ��Vl슩ͦ��*�l�|z�bE�����'N9�i���;��"�?�-o�W����ߺLS��N�]�x��,��t�Vd*6���S?���3�ȷ�+�=uRj.�o;��;K� `�����ʟU����nԙ폧��h�xer���?l�E��ʅW��݅ߊ����BJZ%̏͂�=XzֆT�@�e�����n�VݰaC�gy� >w������Mǝ4����=�m,z�� 13 | I;���8p�՘u���=���~ƺ6��z���YR7����1��#X���0xd����E�����b��s?�q��_����9���|���G��D����!���عݝ3�r��5�7���Xʡ�^a�~�^���ᣘ~�.+h1, �]�t4�+��2�H&���������7Af'�V��O 14 | l�����. 15 | Rv�2�6vz����A�a���~^M����I����@���Zs���3Z�e�1�����3;���ٗA�C�r4�� ]��5}���0��k�/�NX�N���bu�k��MK���y�>�ؿ~������?��Y�s�#�{PY) �r�3���7;~oP]�6���I��Go�YHá��f���u3�S�~�hN�f�e�Sނ.Ml����L�؎�w�@��‹j]����o�� B*|�� 16 | ���T/SP ��}�-����.~g*G?:��U~��[��e�D�(�;�����{`�\��`;>2'G[�d�_vZݥrlE���h�g5�&�wN=z d�Wu�\�Yx�����j��!%�]�d�Ub��8!ǟO�]�A��6I��#JL�:z����5�O� ��{�`�8��#���fv= 17 | �P"��m�60`uq 18 | �v~�5�li5;S�sn$��\�Zۆ�i�쮧�����[�Νx;TX��c[�>�w0U��"���X��w��b��[��$�N���?�ԣ?nx`�ɦu� 19 |  20 | ����[��쐞�c`r?}�30촒�-[ 21 | m`�%'@[0 ��K^d��)-�~X��.��3\F1�Ma��oa��?N2��i�[J�|d7�����Z=�.��W�y˰�v�l�r��Q��|H�ord)�q�@����}�vL=�X���pZ*-�oy[]�kK 22 | �"�O��t�/z�G_ k�D6�D��y�j�=+���p��mVW�||^z�%�fquH[v����(��`v���30��Z8~�L�~j�YV��� ��P��VvkF2d1q��pz �����+����*G_<��J@�j���� X��J�[o����}��.��Γ��֨lϔ��թU��T.�S�`��)Gle;(�8��7�H������HC� 23 | ���8�Ed�Mq͕L�rM�������B��Q�"[b9������rDW+/W�jeG�U��7"�J��E��B)b2弆|�;RrO����;���-#���Y�"�{�U��C��J+;����7^��C8�����EV*F*GJ�q�9�D�vVF>[D�2���%��Q���Q����&WIv��� �z��w+;ʬ�l�L.�Bš 24 | );]큨�(�j�ټy��C�@�RQl!u����k!��])�:`�Yh����d`�J���y�SV�ǭ�Aw`�~9��h�$���X���IK�j�f΍������Շ����1F��c-��9�j���bqΘdtRӃ��TL�ְz�迂�J=��*=�����ϒ��% 25 | :r�js��d����3v���޽>���p�\)@���U�XEG9�x��Ak�eS���K��eQtz�t����YS1 26 | �B�����\5��$+8M��*�Qm5�e n�`)�V�3��$���F��4�Q�d�� 27 | ď�����ܲ�͔�\��$�T���r,�k�d6� �t��k��y�2T/����X���A�Q� 28 | ��6�\�����3���������\��1�ĽX���h�ɼmT��U���T2U�&�r�N���Ū��Q�TIk��U{� `�z��$ � ��� �]9�D�?S�� � � tJ ��N$��l<� � �I B�Q�_z,�д���01D?����~�F!�,W��@V�b۪�6 29 | �^�(I$@$}n96*F�PiZ�Q[��z�NT8���^]�X.+�.1nT�7f2m���s�!�X��s��RŪ���(�z��l_����Yzn�����^�3}ۿ��$�r���d�*V}U�v�F�m���b��Tϙ$J��hiG���΄N�ö��DLS��\��$�4���rTZ��X�Qϖ�J�s���"�-�•Q�v�rU�I��tu�˕:H�J��*Gg�W!빳�es5_�G�.����o�@!�!۬!�yh������a;@�I@�ٳ\)��RF�r��͎K9ټ���ڨ�����s�^�4;ݔ���XΝ��A/�-�B������U�Wy�V 30 | �o��S��Ȭ߬l�,W6��g�j�Ȗ�+���� 31 | b�����*vU��Q���,�m��̬|��sHxS3��Y�*�qښ�v�c�ɍ��X�������;��"���Ґ0��J���?oB�+ 32 | ��?z���Ĺ�.�'�������_O�ljˆ���?C���0�1Ṯ�����c�< 33 | ˕:4�J4�����FSrp@���������t�_�x�R�ȎS]m�v1>L$@)"@�؅�~ۙ+�PJ����_3����V����p�/\� #C�"$@$�#��v�� N����Ү�Ӹ���� 34 | ���W����ֳҕ�� O�W8|�H�H�3T�����^:2��޴� I��(� ������.����>��9�t� � ���c�X_�9'�Xh�&ݪҽ��r�gv����p�9ue$ʒ � tN@�u�6l�<$��g���M}f�5��S���|����O]\��q���4�+A�<Ȭ�߯�@ � �@/XK9t�;7��6 ~���ӓ/��g�3V�ؾ��u���q���w87��Yֽ̚3׌"�[�9rqu�c�t�o�R�JVd�N@]ҫ\�[U����L���%���۷��}N�~Ȃ9D����k|�y�H�H |T�]f,�hd2�}l}p�3�h��g���}��IY����6�$@$@}"@�x�Lc�4m���~��j�{�:�U��l� �e��2��[<��c�@��_c��>⤎�S�w������~L�� ������1���V6����Q��c�Yq�E�]�Y�iS(���C{p��[Y�ڰju�-�Vd��/�o�����C�v[���UF1 MӠiy�; (�F��̒�����n���\��{��3}˕(�8�$�â���'B��ʎ��YTʔ�-��lf�g*�f"!]��� 37 | �[n�.nY���QF^Ӑ-������j��O`X����AL��y�濇t�����%�b���s#z��� ��S.�/��2%ш.+R��ʱ H���.Xmm�ܩ��r�n)�(TJȅ阇V�#˱d��X���b`E��t��ǰ�]��[�s�j7���*+�b���,���{���>���8 38 | -------------------------------------------------------------------------------- /数组/018. 4Sum[M].md: -------------------------------------------------------------------------------- 1 | 018. 4Sum 2 | --- 3 | #问题 4 | Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target. 5 | 6 | Note: 7 | Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d) 8 | The solution set must not contain duplicate quadruplets. 9 | 10 | >For example, given array S = {1 0 -1 0 -2 2}, and target = 0. 11 | 12 | > A solution set is: 13 | (-1, 0, 0, 1) 14 | (-2, -1, 1, 2) 15 | (-2, 0, 0, 2) 16 | 17 | 18 | #思路 19 | 好了,2SUM,3SUM,3SUM Closet 都解决了,我们顺利迎来了最后一个boss,4SUM,但是我们已经见怪不怪了。老思路,把4SUM问题变成3SUM问题。 20 | - 先排序 21 | - 确定一个数,然后文件顺利变成3SUM问题,然后就是完完全全3SUM的解决思路了。 22 | 23 | ```java 24 | for(int i = 0;i < nums.length-3;i++) 25 | { 26 | int target_i = target - nums[i]; 27 | if(i > 0 && nums[i] == nums[i-1]) //排除一样的数 28 | continue; 29 | ……//3SUM问题 30 | } 31 | ``` 32 | 整体代码 33 | ```java 34 | public class Solution { 35 | public List> fourSum(int[] nums, int target) { 36 | 37 | Arrays.sort(nums); 38 | List> list; 39 | list = new ArrayList>(); 40 | int mid,right; 41 | for(int i = 0;i < nums.length-3;i++) 42 | { 43 | int target_i = target - nums[i]; 44 | if(i > 0 && nums[i] == nums[i-1]) 45 | continue; 46 | for (int left = i+1; left < nums.length-2; left++) 47 | { 48 | mid = left+1; 49 | right = nums.length-1; 50 | int tmp = target_i-nums[left]; 51 | if(left > i+1 && nums[left] == nums[left-1]) 52 | continue; 53 | while(mid < right) 54 | { 55 | if(nums[mid] + nums[right] == tmp) 56 | { 57 | int tmp_mid = nums[mid],tmp_right= nums[right]; 58 | list.add(Arrays.asList(nums[i],nums[left], nums[mid], nums[right])); 59 | while(mid < right && nums[++mid] == tmp_mid); 60 | while(mid < right && nums[--right] == tmp_right); 61 | } 62 | else if(nums[mid] + nums[right] < tmp) 63 | mid++; 64 | else 65 | right--; 66 | } 67 | } 68 | } 69 | return list; 70 | } 71 | } 72 | ``` 73 | 74 | 75 | #思路2:排除不可能情况 76 | 讨论区rikimberley有个高分的答案,具体思路还是和上面的思路一样的,但是它的运行速度超过了100%的人,是因为它在运行的时候,排除了很多不可能的情况。假设我们考虑4个数分别为A B C D(有序),最大值MAX。 77 | 1. A太大,退出:(如果4*A > target) 78 | 2. A太小,跳过:(A+4*MAx < target) 79 | 3. 确定A后求BCD的3SUM问题 80 | 4. B太大,退出:(如果3*B > target) 81 | 5. B太小,跳过:(B+3*MAx < target) 82 | …… 83 | 84 | 85 | 86 | ```java 87 | public List> fourSum(int[] nums, int target) { 88 | ArrayList> res = new ArrayList>(); 89 | int len = nums.length; 90 | if (nums == null || len < 4) 91 | return res; 92 | 93 | Arrays.sort(nums); 94 | 95 | int max = nums[len - 1]; 96 | if (4 * nums[0] > target || 4 * max < target) 97 | return res; 98 | 99 | int i, z; 100 | for (i = 0; i < len; i++) { 101 | z = nums[i]; 102 | if (i > 0 && z == nums[i - 1])// avoid duplicate 103 | continue; 104 | if (z + 3 * max < target) // z is too small 105 | continue; 106 | if (4 * z > target) // z is too large 107 | break; 108 | if (4 * z == target) { // z is the boundary 109 | if (i + 3 < len && nums[i + 3] == z) 110 | res.add(Arrays.asList(z, z, z, z)); 111 | break; 112 | } 113 | 114 | threeSumForFourSum(nums, target - z, i + 1, len - 1, res, z); 115 | } 116 | 117 | return res; 118 | } 119 | 120 | /* 121 | * Find all possible distinguished three numbers adding up to the target 122 | * in sorted array nums[] between indices low and high. If there are, 123 | * add all of them into the ArrayList fourSumList, using 124 | * fourSumList.add(Arrays.asList(z1, the three numbers)) 125 | */ 126 | public void threeSumForFourSum(int[] nums, int target, int low, int high, ArrayList> fourSumList, 127 | int z1) { 128 | if (low + 1 >= high) 129 | return; 130 | 131 | int max = nums[high]; 132 | if (3 * nums[low] > target || 3 * max < target) 133 | return; 134 | 135 | int i, z; 136 | for (i = low; i < high - 1; i++) { 137 | z = nums[i]; 138 | if (i > low && z == nums[i - 1]) // avoid duplicate 139 | continue; 140 | if (z + 2 * max < target) // z is too small 141 | continue; 142 | 143 | if (3 * z > target) // z is too large 144 | break; 145 | 146 | if (3 * z == target) { // z is the boundary 147 | if (i + 1 < high && nums[i + 2] == z) 148 | fourSumList.add(Arrays.asList(z1, z, z, z)); 149 | break; 150 | } 151 | 152 | twoSumForFourSum(nums, target - z, i + 1, high, fourSumList, z1, z); 153 | } 154 | 155 | } 156 | 157 | /* 158 | * Find all possible distinguished two numbers adding up to the target 159 | * in sorted array nums[] between indices low and high. If there are, 160 | * add all of them into the ArrayList fourSumList, using 161 | * fourSumList.add(Arrays.asList(z1, z2, the two numbers)) 162 | */ 163 | public void twoSumForFourSum(int[] nums, int target, int low, int high, ArrayList> fourSumList, 164 | int z1, int z2) { 165 | 166 | if (low >= high) 167 | return; 168 | 169 | if (2 * nums[low] > target || 2 * nums[high] < target) 170 | return; 171 | 172 | int i = low, j = high, sum, x; 173 | while (i < j) { 174 | sum = nums[i] + nums[j]; 175 | if (sum == target) { 176 | fourSumList.add(Arrays.asList(z1, z2, nums[i], nums[j])); 177 | 178 | x = nums[i]; 179 | while (++i < j && x == nums[i]) // avoid duplicate 180 | ; 181 | x = nums[j]; 182 | while (i < --j && x == nums[j]) // avoid duplicate 183 | ; 184 | } 185 | if (sum < target) 186 | i++; 187 | if (sum > target) 188 | j--; 189 | } 190 | return; 191 | } 192 | ``` 193 | 194 | -------------------------------------------------------------------------------- /介绍/介绍.md: -------------------------------------------------------------------------------- 1 | #004. Median of Two Sorted Arrays[H] 2 | --- 3 | [TOC] 4 | ##**题目** 5 | 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)). 6 | 7 | ##**分析** 8 | 这个题目是非常的常见,而且有特别多的变形。特别是在当前大数据的环境下,如何快速查找第i个元素有很现实的意义。 9 | ###**思路1** 10 | 很简单的思路:就是遍历两个数组,在里面找到第i个大元素,这个应该还是比较简单的,时间复杂度O(m+n)。 11 | 12 | 用2个变量分别指向两个数组,每次取较小的一个,然后将其指针后移动。但是这里有个问题,就是奇偶判断,如果是奇数,中位数是num[mid],但是如果是偶数,是(num[mid]+num[mid-1])/2。这里我的做法是把num[mid]看作(num[mid]+num[mid])/2。如果是偶数-1,奇数-0。 13 | 14 | ```c++ 15 | class Solution { 16 | public: 17 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 18 | if(nums1.size() == 0) 19 | return MedofArray(nums2); 20 | if(nums2.size() == 0) 21 | return MedofArray(nums1); 22 | vector num3; 23 | int size = (nums1.size()+nums2.size()); 24 | int mid = size/2; 25 | int flag = !(size%2); 26 | int i,m1,m2,cur; 27 | double a,b; 28 | for(i = m1 = m2 = 0;i < size;i++) 29 | { 30 | a = m1 < nums1.size()?nums1[m1]:INT_MAX;//过界处理 31 | b = m2 < nums2.size()?nums2[m2]:INT_MAX;//过界处理 32 | //cout<& nums) 49 | { 50 | int mid = nums.size()/2; 51 | int flag = !(nums.size()%2); 52 | return (nums[mid]+nums[mid-flag])/2.0; 53 | } 54 | }; 55 | ``` 56 | 57 | 58 | ###思路2 59 | 重点来了!! 60 | 这是一个很经典的Divide & Conquer的题目,关键就在如何划分。这里引用stellari 的高分答案,觉得他这个讲的特别好: 61 | 62 | ###**预备知识** 63 | ####先解释下“割” 64 | 65 | >我们通过切一刀,能够把**有序**数组分成左右两个部分,切的那一刀就被称为割(Cut),割的左右会有两个元素,分别是左边最大值和右边最小值。 66 | 67 | >我们定义L = Max(LeftPart),R = Min(RightPart) 68 | 69 | Ps. 割可以割在两个数中间,也可以割在1个数上,如果割在一个数上,那么这个数即属于左边,也属于右边。(后面讲单数组中值问题的时候会说) 70 | 71 | 对于单数组,**找其中的第k个元素特别好做**,我们用割的思想就是: 72 | >**常识1:**如果在k的位置割一下,然后A[k]就是L。换言之,就是如果左侧有k个元素,A[k]属于左边部分的最大值。(都是明显的事情,这个不用解释吧!) 73 | 74 | ###**双数组找第k个元素** 75 | 我们设: 76 | **$C_i$**为第i个数组的割。 77 | **$L_i$**为第i个数组割后的左元素. 78 | **$R_i$**为第i个数组割后的右元素。 79 | ![Alt text](./1460176468429.png) 80 | 81 | 82 | ####**我们看如何从双数组里取出第k个元素** 83 | 84 | 1. 首先$L_i <= R_i$是肯定的(因为数组有序,左边肯定小于右边) 85 | 2. 如果我们让$L_1 <= R_2$ && $L_2 <= R_1$ 86 | ![Alt text](./1460176540020.png) 87 | 3. 那么左半边 全小于右半边,如果左边的元素个数相加刚好等于k,那么第k个元素就是Max(L1,L2),参考上面常识1。 88 | 4. 如果 L1>R2,说明数组1的左边元素太大(多),我们把C1减小,把C2增大。L2>R1同理,把C1增大,C2减小。 89 | 90 | 91 | ####**假设k=3** 92 | 对于 93 | $[1\ 4\ 7\ 9]$ 94 | $[2\ 3\ 5]$ 95 | 96 | 设C1 = 2,那么C2 = k-C1 = 1 97 | $[1\ 4/ 7\ 9]$ 98 | $[2/3\ 5]$ 99 | 100 | 这时候,L1(4)>R2(3),说明C1要减小,C2要增大,C1 = 1,C2=k-C1 = 2 101 | $[1/4\ 7\ 9]$ 102 | $[2\ 3/5]$ 103 | 104 | 这时候,满足了$L_1 <= R_2$ && $L_2 <= R_1$,第3个元素就是Max(1,3) = 3。 105 | 106 | 如果对于上面的例子,把k改成4就恰好是中值。 107 | 108 | 下面具体来看特殊情况的中值问题。 109 | 110 | ###**解决单数组的奇偶问题** 111 | 112 | 其实中值问题有个比较麻烦的地方,就是奇偶处理方法不同,有没有办法统一处理呢?有,还是用割。 113 | 114 | >如果割能把有序数组划分成两个相等的部分,其中中值就是Max(左边) + Min(右边) 的平均数。即是(L+R)/2 115 | 116 | 117 | 比如说[2 3 5 7]这个序列,划分就在3和5之间 118 | [2 3 / 5 7] 119 | 中值就是(3+5)/2 = 4 120 | 121 | 如果[2 3 4 5 6]这个序列,我们可以把4划分成2个 122 | [2 3 (4/4) 5 7] 123 | 中值就是(4+4)/2 = 4 124 | 125 | >**通过观察可以发现不管奇偶数,L = (N-1)/2,R=N/2** 126 | |N | Index of L / R 127 | |-:-|:--:| 128 | |1 | 0 / 0 129 | |2 | 0 / 1 130 | |3 | 1 / 1 131 | |4 | 1 / 2 132 | 133 | >**中值:(L + R)/2 = (A[(N-1)/2] + A[N/2])/2** 134 | 135 | ###双数组的奇偶 136 | 中值的关键在于,如何处理奇偶性,单数组的情况,我们已经讨论过了,那双数组的奇偶问题怎么办,m+n为奇偶处理方案都不同, 137 | ####**让数组恒为奇数** 138 | **有没有办法让两个数组长度相加一定为奇数或偶数呢?** 139 | 其实有的,**虚拟**加入‘#'(这个trick在manacher算法中也有应用),让数组长度恒为奇数(2n+1恒为奇数)。 140 | Ps.注意是虚拟加,其实根本没这一步,因为通过下面的转换,我们可以保证虚拟加后每个元素跟原来的元素一一对应 141 | |之前|len|之后|len| 142 | |:-:|:-:|:-:|:-:| 143 | |[1 4 7 9]|4| [# 1 # 4 # 7 # 9 #]|9 144 | |[2 3 5]|3| [# 2 # 3 # 5 #]|7 145 | 146 | ####**映射关系** 147 | 这有什么好处呢,为什么这么加?因为这么加完之后,**每个位置可以通过/2得到原来元素的位置。** 148 | |/|原位置|新位置|除2后| 149 | |:-:|:-:|:-:|:-:| 150 | |0|1|0|1 151 | |5|2|5|2 152 | 153 | ####**在虚拟数组里表示“割”** 154 | 不仅如此,割更容易,如果割在‘#'上等于割在2个元素之间,割在数字上等于把数字划到2个部分。奇妙的是不管哪种情况: 155 | >Li = (Ci-1)/2 156 | >Ri = Ci/2 157 | 158 | 例: 159 | 1. 割在4/7之间‘#',C = 4,L=(4-1)/2=1 ,R=4/2=2 160 | 刚好是4和7的原来位置! 161 | 2. 割在3上,C = 3,L=(3-1)/2=1,R=3/2 =1,刚好都是3的位置! 162 | 163 | --- 164 | 剩下的事情就好办了,把2个数组看做一个虚拟的数组A,目前有2m+2n+2个元素,割在m+n+1处,所以我们只需找到m+n+1位置的元素和m+n+2位置的元素就行了。 165 | 左边:A[m+n+1] = Max(L1+L2) 166 | 右边:A[m+n+2] = Min(R1+R2) 167 | 168 | >Mid = (A[m+n+1]+A[m+n+2])/2 169 | = (Max(L1+L2) + Min(R1+R2) )/2 170 | 171 | 至于在两个数组里找割的方案,就是上面的方案。 172 | 173 | ###分治的思路 174 | 有了上面的知识后,现在的问题就是如何利用分治的思想。 175 | ####怎么分? 176 | 最快的分的方案是二分,有2个数组,我们对哪个做二分呢? 177 | 根据之前的分析,我们知道了,只要C1或C2确定,另外一个也就确定了。这里,为了效率,我们肯定是选长度较短的做二分,假设为C1。 178 | 179 | ####怎么治? 180 | 也比较简单,我们之前分析了:就是比较L1,L2和R1,R2。 181 | - L1>R2,把C1减小,C2增大。—> C1向左二分 182 | - L2>R1,把C1增大,C2减小。—> C1向右二分 183 | 184 | ####越界问题 185 | 如果C1或C2已经到头了怎么办? 186 | 这种情况出现在:如果有个数组完全小于或大于中值。可能有4种情况: 187 | - C1 = 0 —— 数组1整体都比中值大,L1 >R2,中值在2中 188 | - C2 = 0 —— 数组1整体都比中值小,L1 R2,中位数在1中 191 | 192 | 其实,如果我已经确定了数组1是最短的数组,那只有两种情况了,比较好处理: 193 | - 如果C1 = 0 —> 那么我们缩小L1,L1 = INT_MIN,保证判断正确。 194 | - 如果C1 = n*2 —> 那么我们增大R1,R1 = INT_MAX,保证判断正确。 195 | 196 | 197 | ###代码 198 | ```c++ 199 | class Solution { 200 | public: 201 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 202 | if(nums1.size() == 0) 203 | return MedofArray(nums2); 204 | if(nums2.size() == 0) 205 | return MedofArray(nums1); 206 | int n = nums1.size(); 207 | int m = nums2.size(); 208 | if(n > m) //保证数组1一定最短 209 | return findMedianSortedArrays(nums2,nums1); 210 | int L1,L2,R1,R2,c1,c2,lo = 0, hi = 2*n; //我们目前是虚拟加了'#'所以数组1是2*n长度 211 | while(lo <= hi) //二分 212 | { 213 | c1 = (lo+hi)/2; //c1是二分的结果 214 | c2 = m+n- c1; 215 | L1 = (c1 == 0)?INT_MIN:nums1[(c1-1)/2]; //map to original element 216 | R1 = (c1 == 2*n)?INT_MAX:nums1[c1/2]; 217 | L2 = (c2 == 0)?INT_MIN:nums2[(c2-1)/2]; 218 | R2 = (c2 == 2*m)?INT_MAX:nums2[c2/2]; 219 | 220 | if(L1 > R2) 221 | hi = c1-1; 222 | else if(L2 > R1) 223 | lo = c1+1; 224 | else 225 | break; 226 | } 227 | return (max(L1,L2)+ min(R1,R2))/2.0; 228 | } 229 | double MedofArray(vector& nums) 230 | { 231 | if(nums.size() == 0) return -1; 232 | return (nums[nums.size()/2]+nums[(nums.size()-1)/2])/2.0; 233 | } 234 | }; 235 | ``` 236 | 237 | -------------------------------------------------------------------------------- /分治/004. Median of Two Sorted Arrays[H]/004. Median of Two Sorted Arrays[H].md: -------------------------------------------------------------------------------- 1 | #004. Median of Two Sorted Arrays[H] 2 | --- 3 | 4 | #**题目** 5 | 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)). 6 | 7 | #**分析** 8 | 这个题目是非常的常见,而且有特别多的变形。特别是在当前大数据的环境下,如何快速查找第i个元素有很现实的意义。 9 | 10 | 关注D&C方法的,直接看思路2 11 | 12 | ##**思路1** 13 | 很简单的思路:就是遍历两个数组,在里面找到第i个大元素,这个应该还是比较简单的,时间复杂度O(m+n)。 14 | 15 | 用2个变量分别指向两个数组,每次取较小的一个,然后将其指针后移动。但是这里有个问题,就是奇偶判断,如果是奇数,中位数是num[mid],但是如果是偶数,是(num[mid]+num[mid-1])/2。这里我的做法是把num[mid]看作(num[mid]+num[mid])/2。如果是偶数-1,奇数-0。 16 | 17 | ```c++ 18 | class Solution { 19 | public: 20 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 21 | if(nums1.size() == 0) 22 | return MedofArray(nums2); 23 | if(nums2.size() == 0) 24 | return MedofArray(nums1); 25 | vector num3; 26 | int size = (nums1.size()+nums2.size()); 27 | int mid = size/2; 28 | int flag = !(size%2); 29 | int i,m1,m2,cur; 30 | double a,b; 31 | for(i = m1 = m2 = 0;i < size;i++) 32 | { 33 | a = m1 < nums1.size()?nums1[m1]:INT_MAX;//过界处理 34 | b = m2 < nums2.size()?nums2[m2]:INT_MAX;//过界处理 35 | //cout<& nums) 52 | { 53 | int mid = nums.size()/2; 54 | int flag = !(nums.size()%2); 55 | return (nums[mid]+nums[mid-flag])/2.0; 56 | } 57 | }; 58 | ``` 59 | 60 | 61 | ##思路2 62 | **重点来了!!** 63 | 64 | 这是一个很经典的Divide & Conquer的题目,关键就在如何划分。这里引用stellari 的高分答案,觉得他这个讲的特别好: 65 | 66 | 67 | #**预备知识** 68 | ##**先解释下“割”** 69 | 70 | >我们通过切一刀,能够把**有序**数组分成左右两个部分,切的那一刀就被称为割(Cut),割的左右会有两个元素,分别是左边最大值和右边最小值。 71 | 72 | >我们定义L = Max(LeftPart),R = Min(RightPart) 73 | 74 | Ps. 割可以割在两个数中间,也可以割在1个数上,如果割在一个数上,那么这个数即属于左边,也属于右边。(后面讲单数组中值问题的时候会说) 75 | 76 | 比如说[2 3 5 7]这个序列,割就在3和5之间 77 | [2 3 / 5 7] 78 | 中值就是(3+5)/2 = 4 79 | 80 | 如果[2 3 4 5 6]这个序列,割在4上,我们可以把4分成2个 81 | [2 3 (4/4) 5 7] 82 | 中值就是(4+4)/2 = 4 83 | 84 | 这样可以保证不管中值是1个数还是2个数都能统一运算。 85 | 86 | 87 | 88 | ##**割和第k个元素** 89 | 对于单数组,**找其中的第k个元素特别好做**,我们用割的思想就是: 90 | >**常识1:**如果在k的位置割一下,然后A[k]就是L。换言之,就是如果左侧有k个元素,A[k]属于左边部分的最大值。(都是明显的事情,这个不用解释吧!) 91 | 92 | ##**双数组** 93 | 我们设: 94 | **$$C_i$$**为第i个数组的割。 95 | **$$L_i$$**为第i个数组割后的左元素. 96 | **$$R_i$$**为第i个数组割后的右元素。 97 | ![Alt text](./1460176468429.png) 98 | 99 | 100 | ###**我们看如何从双数组里取出第k个元素** 101 | 102 | 1. 首先$$L_i <= R_i$$是肯定的(因为数组有序,左边肯定小于右边) 103 | 2. 如果我们让$$L_1 <= R_2$$ && $$L_2 <= R_1$$ 104 | ![Alt text](./1460176540020.png) 105 | 3. 那么左半边 全小于右半边,如果左边的元素个数相加刚好等于k,那么第k个元素就是Max(L1,L2),参考上面常识1。 106 | 4. 如果 L1>R2,说明数组1的左边元素太大(多),我们把C1减小,把C2增大。L2>R1同理,把C1增大,C2减小。 107 | 108 | 109 | ###**假设k=3** 110 | 对于 111 | 112 | $$[1\ 4\ 7\ 9]$$ 113 | 114 | $$[2\ 3\ 5]$$ 115 | 116 | 设C1 = 2,那么C2 = k-C1 = 1 117 | 118 | $$[1\ 4/ 7\ 9]$$ 119 | 120 | $$[2/3\ 5]$$ 121 | 122 | 这时候,L1(4)>R2(3),说明C1要减小,C2要增大,C1 = 1,C2=k-C1 = 2 123 | 124 | $$[1/4\ 7\ 9]$$ 125 | 126 | $$[2\ 3/5]$$ 127 | 128 | 这时候,满足了$$L_1 <= R_2$$ && $$L_2 <= R_1$$,第3个元素就是Max(1,3) = 3。 129 | 130 | 如果对于上面的例子,把k改成4就恰好是中值。 131 | 132 | 下面具体来看特殊情况的中值问题。 133 | 134 | ##**双数组的奇偶** 135 | 中值的关键在于,如何处理奇偶性,单数组的情况,我们已经讨论过了,那双数组的奇偶问题怎么办,m+n为奇偶处理方案都不同, 136 | ##**让数组恒为奇数** 137 | 有没有办法让两个数组长度相加一定为奇数或偶数呢? 138 | 139 | 其实有的,**虚拟**加入‘#'(这个trick在[manacher算法](http://blog.csdn.net/hk2291976/article/details/51107886)中也有应用),让数组长度恒为奇数(2n+1恒为奇数)。 140 | Ps.注意是虚拟加,其实根本没这一步,因为通过下面的转换,我们可以保证虚拟加后每个元素跟原来的元素一一对应 141 | 142 | ![Alt text](./1461510936040.png) 143 | 144 | ##**映射关系** 145 | 这有什么好处呢,为什么这么加?因为这么加完之后,**每个位置可以通过/2得到原来元素的位置。** 146 | 147 | ![Alt text](./1461510924594.png) 148 | 149 | 150 | 151 | 152 | ##**在虚拟数组里表示“割”** 153 | 不仅如此,割更容易,如果割在‘#'上等于割在2个元素之间,割在数字上等于把数字划到2个部分。 154 | 155 | 156 | 奇妙的是不管哪种情况: 157 | >Li = (Ci-1)/2 158 | >Ri = Ci/2 159 | 160 | 例: 161 | 1. 割在4/7之间‘#',C = 4,L=(4-1)/2=1 ,R=4/2=2 162 | 刚好是4和7的原来位置! 163 | 2. 割在3上,C = 3,L=(3-1)/2=1,R=3/2 =1,刚好都是3的位置! 164 | 165 | 166 | 167 | --- 168 | 剩下的事情就好办了,把2个数组看做一个虚拟的数组A,目前有2m+2n+2个元素,割在m+n+1处,所以我们只需找到m+n+1位置的元素和m+n+2位置的元素就行了。(在数组中是[m+n]和[m+n+1]) 169 | 170 | 左边:A[m+n] = Max(L1+L2) 171 | 右边:A[m+n+1] = Min(R1+R2) 172 | 173 | >Mid = (A[m+n]+A[m+n+1])/2 174 | = (Max(L1+L2) + Min(R1+R2) )/2 175 | 176 | 至于在两个数组里找割的方案,就是上面的方案。 177 | 178 | ##分治的思路 179 | 有了上面的知识后,现在的问题就是如何利用分治的思想。 180 | ###怎么分? 181 | 最快的分的方案是二分,有2个数组,我们对哪个做二分呢? 182 | 根据之前的分析,我们知道了,只要C1或C2确定,另外一个也就确定了。这里,为了效率,我们肯定是选长度较短的做二分,假设为C1。 183 | 184 | ###怎么治? 185 | 也比较简单,我们之前分析了:就是比较L1,L2和R1,R2。 186 | - L1>R2,把C1减小,C2增大。—> C1向左二分 187 | - L2>R1,把C1增大,C2减小。—> C1向右二分 188 | 189 | ###越界问题 190 | 如果C1或C2已经到头了怎么办? 191 | 这种情况出现在:如果有个数组完全小于或大于中值。可能有4种情况: 192 | - C1 = 0 —— 数组1整体都比中值大,L1 >R2,中值在2中 193 | - C2 = 0 —— 数组1整体都比中值小,L1 R2,中位数在1中 196 | 197 | 其实,如果我已经确定了数组1是最短的数组,那只有两种情况了,比较好处理: 198 | - 如果C1 = 0 —> 那么我们缩小L1,L1 = INT_MIN,保证判断正确。 199 | - 如果C1 = n*2 —> 那么我们增大R1,R1 = INT_MAX,保证判断正确。 200 | 201 | 202 | ##代码 203 | ```c++ 204 | class Solution { 205 | public: 206 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 207 | if(nums1.size() == 0) 208 | return MedofArray(nums2); 209 | if(nums2.size() == 0) 210 | return MedofArray(nums1); 211 | int n = nums1.size(); 212 | int m = nums2.size(); 213 | if(n > m) //保证数组1一定最短 214 | return findMedianSortedArrays(nums2,nums1); 215 | int L1,L2,R1,R2,c1,c2,lo = 0, hi = 2*n; //我们目前是虚拟加了'#'所以数组1是2*n+1长度 216 | while(lo <= hi) //二分 217 | { 218 | c1 = (lo+hi)/2; //c1是二分的结果 219 | c2 = m+n- c1; 220 | L1 = (c1 == 0)?INT_MIN:nums1[(c1-1)/2]; //map to original element 221 | R1 = (c1 == 2*n)?INT_MAX:nums1[c1/2]; 222 | L2 = (c2 == 0)?INT_MIN:nums2[(c2-1)/2]; 223 | R2 = (c2 == 2*m)?INT_MAX:nums2[c2/2]; 224 | 225 | if(L1 > R2) 226 | hi = c1-1; 227 | else if(L2 > R1) 228 | lo = c1+1; 229 | else 230 | break; 231 | } 232 | return (max(L1,L2)+ min(R1,R2))/2.0; 233 | } 234 | double MedofArray(vector& nums) 235 | { 236 | if(nums.size() == 0) return -1; 237 | return (nums[nums.size()/2]+nums[(nums.size()-1)/2])/2.0; 238 | } 239 | }; 240 | ``` 241 | 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /数组/026. Remove Duplicates from Sorted Array[E]/1463063417666.png: -------------------------------------------------------------------------------- 1 | �PNG 2 |  3 | IHDR�y��I� IDATx�� |�����fs�� (*+*"��bU 4 | �W+�˷��?/ (jA�XE[��VlmQZ�Z�������+�W��"b����E�$�@����q&��油�ev�5����\Μ�sfΜ�Y�e� @\'���Q @��� ��T� �Ҋ�X ��9@p�AޥK�@ �s � �R��K+�b!� @��@@��y�V,�B@� �9� ��K�.�X�� �A�s@� 5 | �]Z� @�<� �. Ȼ�b) �y�@\*@�wi�R,@�� ��T� �Ҋ�X ��9@p�AޥK�@ �s � �R��K+�b!� @��@@��y�V,�B@� �9� ��K�.�X�� �A�s@� 6 | �]Z� @�<� �. Ȼ�b) �y�@\*@�wi�R,@�� ��T� �Ҋ�X ��9@p�AޥK�@ �s � �R��K+�b!� @��@@��y�V,�B@� �9� ��K�.�X�� �A�s�&�􎬊���!�u����ʏ@����S���*���I:"�A�<�$\�*)Q�3�ѣ��ֿ��M��*>���r�.��,��:�G�� T��B����d�*V<#_N��/�,���������t�� � n�{��)% ����t�� � ��7��R"�xP� ��J�� �� �{��)% ����t�� � ��7��R"�xP� ��J�� �� �{��)% ����t�� � ��7��R"�xP� ��J�� �� �{��)% ����t�� � ��7��R"�xP� ��J�� �� �{��)%�8��#�Z����$���A>�j��"�b��˖���B���!�|�|��9"4!P]T$��4��E �^�|{���+ �7=RC�9 @ �VII��@p�Aލ�J�H3�ЎO�gt��f9'�8[� ���!wxB����)g^gO��B"�,�|��9 �I �'��!� �,�|��9��g}l� ��|���#`�#��H��Q�"�@j�w�����;5���T� �Ҋ�X���u�+;����t�6yE��y�WD�����L�|�/,%D ��$bs(hZ�ڷO={6��� �n�|���@g ��]?�@�v ��Mǎ /���=���+^ɑ� 7 | �9@ ��{�PF�cR�2����n�Qʃ@� �o&o�|�U�M�|TYD���V��2�n�fʖ"�|��9,��[��x��s�x ��-Jz �&��(w99mڏ�@�e�|�Fl� `��⒴���?@p�Aޭ5K�H��A�=~��'�W�gY��$I @� @K� �@@H�A>�$� ���N��� �@� @%I@� @�wB-�@ @�O*I"� ���j�< � ��|PI@'��P �@���J� �z�S��WΐUR����Z%@�o!�@�B�*���?5�(b���A�ÕO�p�@uQ�݊���P��ey�U(�A@ ,@�K�� ����.�P�� �@X� ��R"���2z�Hɱ9(n Ȼ��)���O��vx.��)@�O�z#� ��(@�o�� @ �VE�2�wO�!H� 8 | �=[�gT�٣�^=��r����.�P��@� T��B}�I�l�_�B� ��D&p�@0��}��ѯ�K H�H�A>��O �!m��+t�> (|� �%ih^ �{��A��G5�!k@�]�v���C��̬�2z��Gr�� � @������{һ>y��Ky/�6eE�aV������~���� ���;��R �+P���T^��s��bC�.@�o�{ �@3e�� ����-�V�L�?�_��@ ���r�(T�� ����[$o�i!��|;��b t�u�Ϳ?��kLk���A�oъ h�A��r��M 9 | d=�^��YMnc��l�=n}��m1�g�]� �v3�@��<�X����C�Zs��'��u����Ï-��?-��=+@���m߅=@����*��T2a�|�;)��������)����2s�>��S��o��� _@�c��;��� C�l?�/yD�ϬR��Y�� 10 | ��i��7��M���Q��׽[��X���Y�e�w�D�0�2w����?Nyw� �N:UY#GȼFg~S��/O�?���c-�I��|����*`~a���5��|����W��e^���(��g2-z|[U��� Вo�[!�@LP/�v���l�//O���:�����5����� Д-��TX�q0�����P����W��C���o�L���4 "P'@���`,���Y���T��3���њ�I�1I/ p��˵O�H��� yF�K<���Aޓ�N�@� ��z/�2eD��Aޓ�N�@� @��B-SF@O 11 | �=Y�@� �@��jy�ƍ��A�/0j�(W� ��ju���js��KcA\���`����K}��7��p�>\�|"� �2���*�� �  ȇ%�D@�ey�U(�A@ ,@�K�� ����.�P�� �@X� ��@� �]V�@��A>,�' �. Ȼ�B) �a�|X�O@\&@�wY�R@���� ��L� �� 12 | �8 ���a > o��qGg���ɗ9H��4�ē ;ViƷ�(Ӹ��u��x��.t��--�s�N��M]2�G�I�уt���zeG��8�����u���U�v�)��h :}���𱊽)C��,@�O2xZ.�����z�2O��U�d9T�C��iQ��d�Pk��T�o^��P�>F�{1���H}����b��ں�+j@$U�t�v���<��f?�����bm~�B��y���{\omߧҨ7U������5o� :�仴�;0 �I�- �[6���X5G#���k�߭��M2h��ś҅}�ׄ��h$�5�����բ���4*��(uh�^�{���3ވf����N��y�n�?��-?��)˴7���A>�nH�x��0P߼h��1Q,��&.�Ig��l)C`�V�9YǞr��7��Gj���4�OGM�}�h���+��>3{���ث2˒e�W��%�zX~T!K���_裨%n�}��-5wx�y:n�l-Y�C{ˌ����;�~�D�ɪ+}���zt{�w���A>ޢi�ޖ{�S7���B������G����C�)M��l?3[�nQ��u�D-z{�6-���������;O}&.һE��҂�5�O�����w��z����O����a�����t�8d@Ϳ�����/-�����g ��z�����Ӷ�f�_D�c��v� 3�]���⮙� VUUն����M 4i@�_�4.S\�^Y���zVm{N���d�;�^���2�z�z����7���0��>�{z��5������?y�.Մȝ��*+[�2� �>�����^ny��*������W�>�� ��7����o���8D��N��l��U�=��Z?@Æ{R�B'I� �$h��{_�u|&S������M��������[��|��L�^��mZ]��?�R]9��=�ܮO81@�������5CI�!1қ��Ż�덕?օ}{���;j\���'�����e��I�%�d���^�����F}ބ+t�g��ޓ��-1޵4=�Ϟ�EOܣ �z�yF��&W��|r�9�(��-z�(\�~���Kj{߇������u F�W����_�O���o�����T� �R~��  13 | ��w��U�o�r���[�]��nu�ԯ�*��ު�^�Sz���?���h��%���|r�9 14 | �lԜ����pDz�����<Ԋ7����40�����p'�����~ ��w~��G /:^ݎ>IS翠�vE�y�������|�$�92�_���C�������'ȧa�%"ˁ'�)�瓯��T���P Om��� ����i���gb N���iiݴ.����ͯ>oz@w��9����3�48w�؆�4��8$�;�U����y�5|@/u�=��7\��=�m��F�������)(�H��|38^Z���DF(ku��>��Vo��~�a�*5�G;�~~-M �L��cb'W���|Œ�C�m�zDF�i�PY�3�wz��;G�9&�uX� �aBw$0x�������"�����v�t�.�u��"�{��Vo�~��am>YL1{��>a����lп��i�C�5崁����y:��P��v��n+Ү�f�D 15 | J��?�rL��4��De7���*Q��q�#�skA Y8O��% a�$���:���.)�HcZ�i\yd@������� l�s�|���X�).� Ȼ�n)m���j��i��˱����#��L!���#�Ek���L���騑�����G��||I \����=w�]T�œ��=Y���L��ߒ�p�-y���C@���v± �N �;��� �� ȷ��@p�A��5D�@h�A��p��[��"���@�-@�ww�6Y�C�z@�+��UQ��z"��C� ��zlU)�@�7ݢ�g�U�٣Uv�� 16 | \#��Uzl����ϲ,+����oܸ1!��������)����;k�*������E���sO��/0%!�%Q@ F���ls���d��!Q'��E���*xv�z =�.ġ�����t�_�W���+{���-�#�$U���I�N��Bnӡ�Ӎ?Tfm�79�|%�o(s��]?G�{�HM9* �@B� auV���.SF�ʝ9�^Ƭ@@>�_]~�^n.�@�mt`m�['W� �\���j�[�X��Κ!_NN�����S�W\���O+���&�a!4�\�7}5�U�X�x%Kp�A����,X%% 17 | \w�2O>Y9S��X���d�}���}�*�t]'P���ʹ�2U>����F��!@�wG=6Y�Ï-Q��b�v�/�s�m����2_A����TVy@�Wΐyݎ ����G��Ƿ��9�� Y�@��)�O�aM+�Т�ʽ�v ���U��#_���U��)����t� �v� E�1�����s�B;>m�KH�A>���Ûg�&Hg�76�!�w���_��޼Fgnݛ�?���:� �@�9�|Oݻ5����P� �B�Dڼ 18 | W>�N�u����h�0�v|��}�8��F�;��Ú�x+V*���F�Y� 2������ y'�B��P~���BAuY�H̔��u�=�ܦ󝷫�g���K�\�B@� 0�����M9��(��u�{��n|�v��8ӯN7ߨ����2� �F�4���d��2��~]��ZKZ��l�v�vf#@�� 19 | p�>���;xh����>�S� �� �P�|By���UR��̑3@�����H" �8O� ��:!G ��E� FA@�yy�� 9B@ .��0�q"~g��#�4'@�oN���B;k~L���, ��;����Ke�{_�۰ �@z �ӻ�R����E)=>Gh^� ߼kc�ߜ?x��kY� ���j! �P]Rb�^}f�,#�� �{���_P�z&@� 20 | �[5d @�� �;时{W��R�#G�m��8 �@���|�F�ܢ��oqe�( �@�A���Ss�A=U^ 21 | �xQ���^��8��Nwq@$ @ ���5y󞼯{7��r!�j���wT���x���bl�L�|2�]t��G+s��.*EA�������)���#���� �.�� �'Zإ����=�ri�(- �͞��mw���[ޘ-H�A>E��S� 22 | ���������[m?���uVF�cҳ@���yWWoz��1=���O&� `�`�^6M՟*��e���CO�P�%�sB�����HX�3v�//�5��{�:ʝ~��'���T%]����"��)��ve����q|� �7��–��%�u;���X��+*׾h����Q��G.8vBMO�}�"��Ah�A��V �� 23 | ܼE9�MU���u��ͩ�o8 �Я�����/�����3��A�s�#[W���oό�tdZ�����n.:̅E�d?2X��݇�_�m���)��\�2zS{���;�~�����#Qz���**처� 24 | Ӣ/�bf��~��X� �H� ߈$u L˽Ӎ7�ˀ����r��������Yu�3��?N��z�ޚa6�`(z���C:��R�����Lյ-k��p�T�Rͳ���8?�ؼ��+�o���os"<� ����E��� 0b�f�?��}�c� �����|"�sn[��tL~� � ER��M��´�N�:�5���y~_ojEzs�X���*���B"w֌���5� �_�z���nn�7����VO��@`�\;���D�!�|��5�,��|�O���o0w��1�L8A� ��Z8��� 25 | ��Z���ھ�o���58�"6��ͫ>���� _��Ae�~���Wg}�n��:�ٯbɓv�ͽnfd3�p�=�kp1a�����r�/ 26 | jS0y4w ��6��u�S�����E��{`:ڝ�^z9�fp���7f��m���'&� @�w@-T�z�͹���g��;�r{_�*?��b�El������H������F����ٳ��[����-��kδ�����͐�f�~Fo�fv|*��/z�Z�����9�{�y%�����t����˒G�]c󮽙�^]�4�8B {���󦈙��92�y�|�O�\:���߿~�4Y ?���ٵ�٭���W�.�W��ѡ_= ���2��­����O��6��ܙӔ������G����2��3��KPou�����x$ IDATGѷ�÷+��`�ؙ�u��]ΥS�4LGAS^ӏ��}�o~ū����<�{��|�j��C�GJ���_5Y2wʔ�8c��g� ��S d� �NM:�o��[��~��G��l��lƼ�fn�w}e� 27 | �]a�p��g0�zx�2;�f_p~�+nS�ȼ�n��7<��Q��{��Ҩ�\x�z�5����̅D��� 28 | ��c�f.:7�b_8d&�B2��̑#켇�k��\�d�:�n!� jj;�!��L����K��o�w���؝MS��@}.7�{$�[p�?����Y�i��vn3̘�~�nnw�V�酞5��fq�N� �����E�5��5�+g���m��W����CNhr��� �����`��7�k�o���ã�]���'�#&�g�U3@N�ǺTb��Θf��g��Fn��ޜ5$U��[���� sQj��Lj8M ��vI�R��j��vǝX=�M��t<3���G%PK&^lw�k*��VF�����Uno��o���\D�W�̯k�^1Sy?�C��n�ϟY��~d�3�B�<��X��~�`z�g�7V�Ϭ��٭�gٷ�M�?������J�$�-6���sAb:��/~�m�R(`~����o�0����&I[����̭蘓锶�f��mL�7�f�Ns�w��Y�ƾ�mZ�)<0M�o�Ӭ���}G�����<������������������7�܌�o�#�o�)`~��g&sG �w�ܦ�/f2�ʙ4Y�n������3D+�?m_� &@�����$tmx��[�ߧw���u��2���:��� ���z�[��C�F'f�1ִ�s��4zUd��ҝ��n������I#�Θ����v�L�7���o�0?�cn��p�|] �5�\e�uF$ �m��ߏ|o�L��/��|�����mٗm@/ 29 | �,˲�Xp'����7�gn=�g���y[&sk�b�rU�{���:S��u���ڒnk�5������[�_G�1?�c� �ժ��e@ hɧ����hno���hm�J�%�e�K�d��75�]��b�"�_�K��HHw^�Ka ���y����s.�^ 30 | s�>�6��4p'}rON@�� 31 | p�>�� @�� ВO5B@ ���zs4@�&@�O5B@ ���zs4@�&@�O5B@ ���zs4p��$���N �;�&��������u��}9(�{���KJ�)m�?���:�����=���[�����ڽ?;"o�|�EI<)`~F��E&Aޓ���B��Z3� �J�:Xb�ח��V�&�� Ȼ�~)$I���&�'�p�V �[��F ���A>���#� �*�|���@�� ȧ_��c@Z%@�o!� �~���3r� �@���bb#@�O� �~uF�@h�A�ULl� �@� �ӯ��18P�ڷ�Ε�[7��,yU� �՚�� W���E�ȗ�9��� �wD�}@��wݣ�M�4[����p\�۰�d ��-��@ �:�y����쟒����'ە9��X�Y�@J�)a�� �nYg����/�̶��툘�Y�@*��P�� �vY�|[O����P(����wT�狘�Y�@����%]p��� 2��B�6*W��}���>��3�Z��2z�h H�A>�¤��Țp�*W�lT�ЎO�e�'k�.pӭ�<��F�Y�@2��P� � 32 | ��i�����1;��rs����cKd����`B �T�sLHK��=�9�U��[��n�@���W��紸- �(�|�dI\)�5�\U���ٲ���ʦ�R��'+{��f�e%� �'R��@�uYcϵ_��呲���L�|=���I_r�%��wy��'� 3�B� � 33 | u��i+�?��=�M���#e�������+�~�J/�&���*x�F��1�*�|��9.��@�逷�Q�S�)�y���Z����(k����qưO��uW�}�eY�*�A/P:�R��wS���X�8GV(��3G���K�O�|��4oK� =����4��tt����m�E���� �,��b 4Q�@�[Z:�B�Է��dֺ��Up� �>}�^�hb/,*�X/̟����찋O�Gk���5�����S���&E��R"�aÆ���A˶Z����ʒ,E��g�~��VI��2��W[�G�h`�R;�5кz��I51K��}�g������3��?�:���VY�eRe��zw�D�OV .��?��ֆ����I�9ЖCzͅ�|�\��7��X5G#���k�߭��&������O��Z��ڮ�O���>J�b�9�{�h�9G>U ��Ρ�zm���?�x�E���������V��)��S���L{[ d5� �'B��io�C��-�;�CRVM\t��tr�������� �#O���]�ͅ�eY�����`�������\�>ԯ歐�����Sݳ�h��%Z�c�ʌ��_�����a�u.*���!/\�����2�<7f���ߡ�e��R��Z�h��d�є���G��}g�d ��%���l��?uÚ*$��1[�~�M�]?D����d�����#5b�����#-��<�ܷ{MV�z�[�ݪ��WhrT< �^�gR��$�����S����n�.���r���Syv�������{�����������>'P����i�K t����Y����5������Y������ۑ/� �4�|Ҩ�q��������ھi�& �������(g��/�Ԧ��#�b�zUݟl���}��^���2�z�z ���i\A�5��sU�?�Go��ۖ�\�}�¿��Q�jB�p�C�� ���@��ɳvđF��� 34 | �v����+��mG��y�9�x�e�9�;q�z; ��B`��D��а���!��@��H���U���̷Z`˶ϣ�=V' �����O��=������"_<�]��q�zF���p+�#�h�|��I?���KÑ,Og��1]�+����>���|+r��߬���S����k���+�Z���[���+tJϾ���W��ߜ!@�wF=� � 35 | >���_�� ���j�L��*�Qs�^�������_��P+ޜ�5��`͠I�A�����d���G��p�v��K�k�2Ƽs�?s7�� ��ڥl�� �+�I�?`������N:�|��]�'�;^ w�ު��G�-�(�\�����їk�K�T��, �4�K���;�Z�V:9OS�|�V�N�@��z<���r��\1V3��|4{�_=NP�}�����ֺ�G��Q�RX�M J�:�|��9�S����Yۄ���m&�I5~���W��4�巴�&|�3���c4 �v����� I �'�����@`������o�U3c�w�6%�`F ��{g(:�_�j��6�&6 ۹�r�݀�$V����K��$ب��������~hm �_�'&��k����ZM ����x���Is� 3����Q���9�,���;��Ɲ�#��&@�O�3<�xE��hm{~C�[�mn7r�(�kxqo�w����am>Y� �S�p� ����=���mZ��lM9m�z�GE|���3Tc�ݫ�ۊ�빙:�����/�;�L�zw�c�K�wՋ 37 | ^��ͽ����*��{��m)��yz/8�-{xk����y�-���V�)m: ВO��"� ��A� �,6E�-��+߸'�Rʁ1�1`X�������n��ՕL��x&�Y��F�\����3�^�^���O��Z��d��@�W�E�q�Eϝ���X�@� ВO�$�tH�zZ�"dg,@K���C�@��A�#z�� ������� �@G��c_@,@�wp��5@:"@����"� �`���+��!� ��eYVG`�� lܸ�};� �@�F�ա��ig�|:�yE@� ܮo��S ���]s�*W>��R*��A޳UO��@���*�z���-��L�S���С��������v��X��|]��y�B!��zGT�H�@�����9�u�O����TZ���~���s@ ���rs�T X�r~t����ߧ����V�Ç)���T��r����Te��"� ��|�hI�)V��p��}_*�7�)��ɑ�e�뫜����#�)����?���:f@�t�%��5H���T�߷�*)U�������� 38 | u�u�|*�����b- �f�4�0��6�C<��W_W�o��?h`�������;s��]����m�@ ���\{��Y�ʵ/���G�;�Je��x�@ydY�Y3�9r���>�yKd93 �@: �ӹ��{L��(v�'��N7ω��//�f]�_]yоm_v�U��sV �s�h�I�G� �d ��%�q�&�p[M/�A�������4y���=����Ⱥ�=��w��ze�g���gB ^��s��P��<�$I��-�A� ��v�c����e��u�����"���Qo�y�.����nu]}m�u|A�#���ݾ����EG�a_�$�+tm�b�t���~e�/f ޔ��e �W�x�������"�Ͽ_U�7(��3ҡ����Ycϭ�an� I�~�����A���j�2�0��cݢoh��܊7=뛚r���.�-V� ��Z�2�-�{���>P������Вo��zJ�������Se���h�*g����,@K�˵���W����|F��|�&s���Y>@�� ȧ]���xT��c'������x�4@�T �S]?%VEeJ��A@�d 39 | 䓩ͱ@H�A>�� 40 | @�d 41 | 䓩ͱ@H�A>�� 42 | @�d 43 | 䓩ͱ#`,����{�[�d�� �� ȷ���[���/�Q�|ݻ�wA�= ЌA�V�W���}=�ro) � �i�@;����kڱ+� �I �'���I�r�:^��ME�, �B�� +�"!� `���C�*��B���. �d�|��9�3::v�(�UQ�� @ �A> ��-`��9��2�s�J��@� 44 | d&0m�F��]Z�ؼ�1@ ^�xI�NZ ���.�*��"�@��]�.6v���UY)_n��(?8\� �� 45 | "{�}�]�����9r�� 46 | �9h�@����p\;�d@ y��Ys$� ���]V"��h��=_(���D����#� ���Z�A���knH�AH�� |E�5VI��C� �sxɓ �Ӛ 47 | q�6���ݡ���U�Yg� 48 | ��[��2���*��$G�� 49 | ��{���\D�^q���� =�'N R��s\�A]׭���~���+q�#e������sU3e���Ҧ�����Sz� �v|���K������ʾ`��U(z����x- C:��b�\t���2�?���ݸN����3��̓:8v�*W>��6,u���4��9� 50 | �]����(�s�����ǹ���YygՇgsc�(����ۛ�~��ma:+�ۢ͞K�ƷT���U��E;�����|��ы�5ߪ��`���~��E�����{p��:;���9gK&]�̡�R���"}7L��WP`��,�NG�|:֚ �\������r7�:�7��-���S"-�&�m:5��v�N����V6}�N�X���E67A�L�Gi�;U�z^�y���MG9�;�x���C�O��~��*�?]/�fCs�b.x*W���K� ��)�>M;S��V�ݞ�����RU��A�3U����~�~���7���'�s�d;��A�ہ��foj�\��@�u�*X����fn������摟����,kˌU|@�yw*g����ʹ�/~T�!'��M?�?�'_���wt��%��5�\��V����� s'üjU���7�h� !`.�*׬U�_�R�eS����>��3�R#$T� �P^o��i}�� ح�LP,��~�h���V�COT���a���ߊ۫g�Em�����f�..�?3 51 | 52 | �e���������Y��y��۞}TS��{��lw���1���F.X��|ܾ� nޢ�˦ŭ,��1w��Q��ԛ��cB�)y���PF�ʹ��VK�[��Y~���D�{����3F�� ��Lp7-��^u=����}]����ٯ�e����ac�K_���z����g��o���?/�I���5-Bsg�bɓ�4�AZ+@�o��%L�tH�.*R���[�Nx0�Ï>._�n2�����G��B�;ɱ&s �j�+�VG��������ǷD�Ś1-y3�I����\������5�{ᛀ�{���b��}���Ǘ�[�@�5��(�MB-��U�;�G��cZ����ӌi�. ̫r�El��mZ¾����v�o����;�&0ǚL�f[s6{���fVmG>_�nuˊ�<��Yff�|yy����:s7 |���gO8_yw��&o��7��=k�1�ƙ�kk��[δ�[}��N'���/����0�]|�@�/m:�����W�α�]s�0!�(�eYV�']�0����3��C��舍��=nZæ7��A�������f���n�23� ����s{s�`��7����w��k���f;p��}l����U�۝��]������!:�iZ�fl~3����y��0GC[?PF��MލJߒ�s� ��V#�O8ț� ��O/kS�M@6���be���Oh��|�఍�c��N:U��f�c�;,{d(��zV�W���q�};��c�����r/z�Tf3ou��m���e= @��@@���B�Ҋ�X ��9@p�AޥK�@ �s � �R��K+�b!� @��@@��y�V,�B@� �9��H� ń@"���%m@ �@Ŋ�*���kY�@|��q$@�MU��Wք�۴#�V�|[����@0��7ޔ��qM��hV� �,+@�� �>�.����F���I�(�|� �@2�KJ��d�Ꙍ�q  �=\�@��yw�/�C 55 | �[�L$C� � e��D X��QߘE q��ْ2 �) ȧ���#� �8�|�lI@�� 56 | �S���@H�A>q��� �@J�)��� �$N� �8[RF@ ����sp���ȗ��ŢS�$ �� ��@3���s$C� � e����t��� 57 | nz���� 58 | w)��~�n�J�!@���"i �F ӯ� �ס_-h���Ԭ��f�a%� ��C�4@�Z����+(P�ޢ�&�����1׳�x ��%I: �@�@�駪r���{df6��2�5 5����U� �V1�GZȾh�/[��VV�ܾ���ܹ�z������ 59 | �c� ȷG�}@�f2z�PF��Mv� n|�n�g�zJ��ݡ����z]#�W� �^9�C�Ⱦx�=������̅@�T��-�~GYcύ^�< �w���@��r.����-�v� �iޛ/�>K9S����@\�qa$@����.�;cT��o�W4� ����ѽ�:͚�p-���A�C|����:�TU��J� ��b���YX�o�N�X�V}�;o�,��_��A�x��4'�=�|�~W�{��l�������ܢ/�l����?<ʳ��3��Y�e�3A�B�(�=W>�_y���^x��I���՟���� 60 | ��T�!'���q ����@�����������>L ��[w�|>�?�Lf�<&%���K�:�"���}��/���+g�?x��VF�uY����H��Ά�� �|s����-et�U�_��/7W]׭����΁T��w���� ����)����.)U��W�=S��/(��S_�< `ƥ�z�Me����RD���R�@�8 p�>Π$� ��S�N� �� �@��q%9@�"@�wJM�@�,@��3(�!� ���Sj�| � g�|�AI@���R�@�8 0v}�A��ƍ�,i"�� 0jԨ�p�j����'��t?�"�㌹���1(.�M�K� K��ĥ�G��qI�����^��@��0,F@ ���^��@��0,F@ ���^��@��0,F@ ���^��@��0,F@ ���^��@��0,F@ ���^��@��0,F@ ���^��@��0,nZ�x�|�;:[>�O��A����������4��tt����m�E���� �,��b/(4.c��--�s�N��M]2k]|��ҭ�N�p���U�@��ܿ��c�0�Nt� 61 | ��.>e�A�O��>�GO��}*Kh19^`Æ ��c�V�w�XY������o�.k)s�|�5{T��.��Y��W�t������zv��H�sƬ�[_����|�J��~��E�>Y-����SkCY�O��$��m=bjΗ�����iɧ� 62 | +-�ЎUs4��ɺ��ݪJ�<'2��i���p㾖-�����&讏�礽z�p]���������r��޼�� ]�~���ѩ7<�ݭ��S���?e������ y'ԂS�P�YM�o^�P�Y}4q�M:ө�MJ�v곢����'^�{���)W�; �՚Z0QO�v�oT�����~�e��ԉ����]���l���/�}�^y:�׏��^16v�����X�*�W���������F���#=�\)Q�P]��n�A��R�Jwo�� ��)=�j��vx`\�|M�A>a�$�9��'����#}���>��3�v�u���� �bdY2�l^{��‘ 64 | ����w��1��#��I�y�kM� ��_�O�/��1} �j���t��,c�;���HP� � �%Y� 6j����W&���Z�׫�8��GTq̀/'�w��T��7V��~h��q�w�p��WG_�/�R�k�4 |�R���N�e�,� ȷW�� >ЯǏ����\����u 4�S���}�i�̿���(����g���퇵��Q�`���E��A���vӱ#�����Y��,�~������h�<]��En�KEڽ'z�w���?F"�߯/vE�0�@����cG� 6�����L���_53�x�����U.�:wQN��,A�C�'�!>v��@`�n~���^;�zm �����;ۢz��T��-���-�oV�8�G����B�'����N�\'P���vV���/z��w�hu�{����kq��명��m% �]��W _��c��9�Zx-�p�fܼ���'�l]4�u�r(P 65 | �)@��i,`zџ6F�k;����@&�{����{���n8�hu���Y���� 66 | |3��Z:�;:��yz�v�v)_�:C��th1�;?�?�����nG����_�{;�"��x�{za�T >e���=#�\{+�������v}k�<�M��q�:m]͘�Mj��>-�^��j���Q���E����C�{�K 67 | �_�i��4��2��ԃ��� .m�z��*TH!>}Y �x��y��ǯ�O~\�/u)H��'Q?���N�ڷUO�����W6��?�'��O�y��uX�VZ�m���m�G3>D�g�c����<�G;]܋<�?���?Ny�w���m��1{�6����#0����Q���e������7������X�&�|����qM묍e�� �o�.����q��siK��������迖�Կ����r�4��GGDG��|�x���^���S�M .p��Ϗ���=���mZ��lM9m�z�GE|3���3�^��V�]�y��{����m�#�����yd���^T�*���Ŝ�\%���n����z���?7�y�����7u�u ���ߐ��W��||=I @��Sd@�� 68 | ���Ij �8F�  # ��W� _ORC@�1y�TA@ ���z� �� �;�*� �� ��ד�@p�A�1UAF@��A>���� ��c��� 69 | 2� �@|���$5@#@�wLU�@�+��,ˊo��o��7�;I�Ch���Q�Z��s7!�;�n� ��v}���@� 70 | ��[7� @� �;��� В@��"Y-m�zH�A>�$���!n�E�N����R ���crH����Vի�u��u�u���SD�'@�w^��#�Z� 71 | ���?/S��m�������M2��ܮO�$�8H�r��tp�D��@VU�|]��;����xO�{uN�����\��[T�~���:C��W���JYY*X�B=z���$�- Вoو-@��ʵ/ڝ�B;>U��+��K����ƍ�u��J�^aw�k& V!�@�� �%Y� P���*�>K�����[������]Q��_ߧ�'�U��/u˙C�� ��F́p�@��Bn�U�#G(���m��]���������U|�]��4 ȧA%�E'`�����.�<(e�cf���o�UR���n��}L%V ��|b\I� 72 | C*��Z�{Oy���d�:��Ǩ���2#�1!�@b���%u\%`�t�u3�-SuQ��>�g�F�e���.�'~A�/�Gk��8 �� Jr P+�ǽ�q:b�K�u�Gk8WH�A>�¤����`��g��3uJ�۱tH� �!>vF���g���}z7\U��/�s��|A�� ��oJ�xZ �L����Rd@�x ��-Jz �8D�   ��[� oQ�C@�!y�T�@@ ��x��0�֛���(�KP|R/@�O}�\%P�� ��g}9 ƮwU)) �!@�O�z"�����.';}�KNp�A�ŕK�HG���-*��}��u�������2���B;?Uh��F���I� 'H�A�8 ��n�t(�A��y��0�C �½��,�dG 73 | �Y-d 74 | ���>p@��*@u����� P#�  O��1窣?#k��i!�Y��g���#���˦&&aRE�6 p���d�� �@z�ӣ��%��|����=S^ 75 | �@"���%mh�� �?��6�� �X� �؄% �B���be�>&�9���G� �$ �� ���� xB R��}�(*���A���O�p�@uQ��S��̘ 76 | *��-Y��D��H��ɧ� 77 | ���� ��5?�(!�����'MLH�$���h�;�6� In������5���z��)a.L��@�e�|�Fl��kB�l���ƪd�d}5� �̓*� ���� ���oE�_:�R)�P��� ��^Ô���k_�qp�;*��)ӯ.?����T���f}B��l�,��*�l��;�ѓ�����2�u`��`H&o-M�{�P�e�dUT({��2���?�����A���O�� p��'�<���A���2�yt���x��v5�K'O��H�����?|�����ف��|7A<�T�̳�-��˦��1��c���1��ͫr �.�#��50��s�w�>k��ȡ�,�_���E�G�dO�`�~��y� @�wC-R�0-�p ���جѢ���홣N�;�����N��ɻ�Ne�uF�>����m7v��+.S����O�\4�L06�|y��;kF�զ#]�����;�m����mk����b#������.�_�˽�2�c�Yh:�E�������ι�|� �"˘A�My7�&eA J �~C�[�9ߎ̇g2z�tn �� �f� ԡ�wٛ��r�f�U��=ʽn���m�L˻�����ev綜�_�ܙ��`m�ox��< 78 | 0���Θ��_/M���W�����1�8���Z7wL;s��\��������5�*����L�c�.�?��J\�� i���� *]Jр v�BW 79 | ��K���`1؅҅kQ�?��G�#�oȌ�$F����BH&s������{ι'�KLl~�>�� �d�q[ I��Ft������y��� �n���v��*�_���O�����wq�ĝl�2���-����`���e�����������ջ�ei=Rǹ��ُ?�Ϫ�<}�t?x��w귖>�wڝ�W�C��>u�`��a�s�q���"aa�ީ_���kC3/�(7�}�oOOh�����l��W_��W`� y�� �����r���@L@k�|��ŝn,(���Z>P��gn�>*�����qc�z��w3�����^w�T}/��c�=W��;���{٦�z�G>��IDAT^t��{|����)?��c�ڳ�k��B,�s�̹z�]�C� 80 | c��̉A�D��7c����p'?���� ������R�.&�m����˗J���9�.����������&��׾�0��}s]��c��ƏcE7���K�����:�»n���n-�t���zQ�z��:�����}���y�պo�(�����S���!.F��?�7�-.rl��,5�� 81 | ������{��v�s3+�y�c������������+�1���p����>z���{^]���z�:�ۭ����u,I��a���?Љ w��L{��B��|������د�0_�f���>5Ӯ� ���Ng��1� �ȍޏ��g#�E`jccc#Ka����@Ll�������Vˡ��3M��77ר� ��'_�w���mF�'���bۿ����{��_�#s1/ ����-�,b���p���,���Ԥr�*�� ���f�o�u��+��t�v]��^����;t���B7��_h��N����x#��k�������>B��0�'A������K/�p���٢<�i���1&�3�xf~��&� Ε�����Q� �+ꣀ��u���P��B>e�*(Ew�V@�� 82 | ���X @@�k @ ���OZ��E���6@�� 83 | ���X @@�k @ ���OZ��E���6@�� 84 | ���X @@�k @ ���OZ��E���6@�� 85 | ���X @@�k @ ���OZ��E���6@�� 86 | ���X @@�k @ ���OZ��E���6@�� 87 | ���X @@�k @ ���OZ��E���6@�� 88 | ���X @@�k @ ���OZ��E���6@�� 89 | ���X @@�k @ ���OZ��E���6@�� 90 | ���X @@�k @ ���OZ��E���6@�� 91 | ���X @@�k @ ���OZ��E���6@�� 92 | ���X @@�k @ ���OZ��E���6@�� 93 | ���X @@�k @ ���OZ��E���6@�� 94 | ���X @�Ov -ߋx,PIEND�B`� --------------------------------------------------------------------------------