From 9b4ae7c685b92b2d48b66c51db700cd478bd5c9a Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 2 Feb 2014 15:26:06 +0800 Subject: [PATCH 001/327] Create test --- test | 1 + 1 file changed, 1 insertion(+) create mode 100644 test diff --git a/test b/test new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/test @@ -0,0 +1 @@ +hello world From 837679f4dae1f11e5d08e6a06c5dc11bcd9e6fa4 Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 2 Feb 2014 15:39:24 +0800 Subject: [PATCH 002/327] Rename test to test.md --- test => test.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test => test.md (100%) diff --git a/test b/test.md similarity index 100% rename from test rename to test.md From 1cf8e3534fcf7472b638213724db54bdf1706ab4 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Feb 2014 16:06:57 +0800 Subject: [PATCH 003/327] Update README.md --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 391401c..0e1c27d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ AlgorithmNote ============= +Introduction +------------ +AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路和解法的Github Blog,主要对相同和相似的题目的解题思路做归类分析,文中涉及的题目来自Leetcode,微软100题,剑指offer及各大算法博客等。看完此Blog,都拿大Offer! +Chapters +------------ +1.排列与组合|keywords: Permutation, Combination +Core contributors +------------ +[@sc703bupt](https://github.com/sc703bupt) +[@popolou](https://github.com/popolou) +Contact us +------------ +欢迎提出意见和建议到sc1_1@bupt.edu.cn . + From f71dfbf735c48be112f6380b92152334b7e0c77d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Feb 2014 16:09:35 +0800 Subject: [PATCH 004/327] =?UTF-8?q?Create=201.=E6=8E=92=E5=88=97=E4=B8=8E?= =?UTF-8?q?=E7=BB=84=E5=90=88|keywords:=20Permutation,=20Combination?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\347\273\204\345\220\210|keywords: Permutation, Combination" | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 "1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination" diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination" "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination" new file mode 100644 index 0000000..4d6c37a --- /dev/null +++ "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination" @@ -0,0 +1,2 @@ +1.排列与组合|keywords: Permutation, Combination +========== From bbff46cab5910459967db83865b194f8aa0ec88c Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Feb 2014 16:09:56 +0800 Subject: [PATCH 005/327] =?UTF-8?q?Rename=201.=E6=8E=92=E5=88=97=E4=B8=8E?= =?UTF-8?q?=E7=BB=84=E5=90=88|keywords:=20Permutation,=20Combination=20to?= =?UTF-8?q?=201.=E6=8E=92=E5=88=97=E4=B8=8E=E7=BB=84=E5=90=88|keywords:=20?= =?UTF-8?q?Permutation,=20Combination.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...347\273\204\345\220\210|keywords: Permutation, Combination.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination" => "1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" (100%) diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination" "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" similarity index 100% rename from "1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination" rename to "1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" From 513d95dffa2042be01abc28b496eac4490107b8e Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Feb 2014 16:11:28 +0800 Subject: [PATCH 006/327] =?UTF-8?q?Update=201.=E6=8E=92=E5=88=97=E4=B8=8E?= =?UTF-8?q?=E7=BB=84=E5=90=88|keywords:=20Permutation,=20Combination.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...7\273\204\345\220\210|keywords: Permutation, Combination.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" index 4d6c37a..1e0fb59 100644 --- "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" +++ "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" @@ -1,2 +1,2 @@ 1.排列与组合|keywords: Permutation, Combination -========== +--------------------- From 3267b65227d9cf017410f6bfebc7227736f03eff Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Feb 2014 16:12:46 +0800 Subject: [PATCH 007/327] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e1c27d..59984e3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ AlgorithmNote ============= Introduction ------------ -AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路和解法的Github Blog,主要对相同和相似的题目的解题思路做归类分析,文中涉及的题目来自Leetcode,微软100题,剑指offer及各大算法博客等。看完此Blog,都拿大Offer! +AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路和解法的Github Blog,主要对相同和相似的题目的解题思路做归类分析,文中涉及的题目来自Leetcode,微软100题,剑指offer及各大算法博客等。 + +看完此Blog,都拿大Offer! Chapters ------------ 1.排列与组合|keywords: Permutation, Combination From 18159d6c469e7735b722951b3341feced9660611 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 17 Feb 2014 10:46:37 +0800 Subject: [PATCH 008/327] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 59984e3..01bc25a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ Introduction ------------ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路和解法的Github Blog,主要对相同和相似的题目的解题思路做归类分析,文中涉及的题目来自Leetcode,微软100题,剑指offer及各大算法博客等。 -看完此Blog,都拿大Offer! Chapters ------------ 1.排列与组合|keywords: Permutation, Combination From 91f6db65c94b658bc33039557fbba491e6c0093d Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 20 Feb 2014 21:14:58 +0800 Subject: [PATCH 009/327] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 01bc25a..33718b8 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ 1.排列与组合|keywords: Permutation, Combination +2.字符串dp与数组dp|keywords: dp Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From dcc66da47438879d1a2fd14e374f8e676f44877b Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 20 Feb 2014 21:15:28 +0800 Subject: [PATCH 010/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33718b8..a3f2eef 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ -1.排列与组合|keywords: Permutation, Combination +1.排列与组合|keywords: Permutation, Combination 2.字符串dp与数组dp|keywords: dp Core contributors ------------ From a595c84d3f823a8eb513df24a6aa547d2f7d54f5 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 20 Feb 2014 21:28:36 +0800 Subject: [PATCH 011/327] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3f2eef..43ca790 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ -1.排列与组合|keywords: Permutation, Combination -2.字符串dp与数组dp|keywords: dp +1.排列与组合|keywords: Permutation, Combination +2.字符串dp与数组dp | keywords: dp Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 13a90f6b4ea8cdcaa4173ccd444a1a1e1f3cd862 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 20 Feb 2014 21:30:22 +0800 Subject: [PATCH 012/327] =?UTF-8?q?Create=202.=E5=AD=97=E7=AC=A6=E4=B8=B2d?= =?UTF-8?q?p=E4=B8=8E=E6=95=B0=E7=BB=84dp=20|=20keywords:=20dp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" diff --git "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" new file mode 100644 index 0000000..cbdbdc1 --- /dev/null +++ "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" @@ -0,0 +1 @@ +2.字符串dp与数组dp | keywords: dp From 255258fde82a981c0fb14d29d2e8d02181a056a4 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 20 Feb 2014 21:40:43 +0800 Subject: [PATCH 013/327] =?UTF-8?q?Update=202.=E5=AD=97=E7=AC=A6=E4=B8=B2d?= =?UTF-8?q?p=E4=B8=8E=E6=95=B0=E7=BB=84dp=20|=20keywords:=20dp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" index cbdbdc1..13602ff 100644 --- "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" +++ "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" @@ -1 +1 @@ -2.字符串dp与数组dp | keywords: dp +##2.字符串dp与数组dp | keywords: dp From 13a23086911f281e65534adc6f0b125daefa49a2 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 20 Feb 2014 21:43:36 +0800 Subject: [PATCH 014/327] =?UTF-8?q?Delete=202.=E5=AD=97=E7=AC=A6=E4=B8=B2d?= =?UTF-8?q?p=E4=B8=8E=E6=95=B0=E7=BB=84dp=20|=20keywords:=20dp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" | 1 - 1 file changed, 1 deletion(-) delete mode 100644 "2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" diff --git "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" deleted file mode 100644 index 13602ff..0000000 --- "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp" +++ /dev/null @@ -1 +0,0 @@ -##2.字符串dp与数组dp | keywords: dp From 631a8dad525969971310a43c90a91fb9b3deabc7 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 20 Feb 2014 21:44:09 +0800 Subject: [PATCH 015/327] =?UTF-8?q?Create=202.=E5=AD=97=E7=AC=A6=E4=B8=B2d?= =?UTF-8?q?p=E4=B8=8E=E6=95=B0=E7=BB=84dp=20|=20keywords:=20dp.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...62dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" diff --git "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" new file mode 100644 index 0000000..a66b3bf --- /dev/null +++ "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" @@ -0,0 +1 @@ +##2.字符串dp与数组dp | keywords: dp From 5d13ed8263f77d27e26e5ba46318f70e9c3bca7b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 20 Feb 2014 21:48:33 +0800 Subject: [PATCH 016/327] =?UTF-8?q?Update=201.=E6=8E=92=E5=88=97=E4=B8=8E?= =?UTF-8?q?=E7=BB=84=E5=90=88|keywords:=20Permutation,=20Combination.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...210|keywords: Permutation, Combination.md" | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" index 1e0fb59..b80b5e9 100644 --- "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" +++ "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" @@ -1,2 +1,24 @@ -1.排列与组合|keywords: Permutation, Combination ---------------------- +##1.排列与组合|keywords: Permutation, Combination +###*Permutation +一般来说有两种解题思路,一种是利用递归生成所有的Permutation,另一种是利用求上一个/下一个Permutation来求出所有的Permutation。该题有可分为有重复和无重复元素的情况。求上一个/下一个的方法适用于有重复和无重复的情况,不需要做适应化修改 +而递归方法在有重复元素的情况下需要修改为对当次递归相同的元素做跳过处理。 + +Ex1:[leetcode:next Permutation](http://oj.leetcode.com/problems/next-permutation/) + +高效的方法求下一个Permutation。可以这样理解该方法, +```cpp +void nextPermutation(vector &num) { + for(int i = num.size()-1; i>=1; i--){//改变右起的第一个升序对可以使序列变大 + if(num[i]>num[i-1]){//num[i-1]和num[i]是第一个升序对,此时从i到size()-1是降序 + for(int j = num.size()-1; j>=i; j--){ + if(num[j]>num[i-1]){ + swap(num[j], num[i-1]); + reverse(num.begin()+i,num.end()); + return; + } + } + } + } + reverse(num.begin(),num.end());//说明是降序,直接反转为升序为最小的排列 +} +``` From 2ef9316afb6a0369246de422ed1bd60fe9aaaf3d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 20 Feb 2014 21:50:45 +0800 Subject: [PATCH 017/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43ca790..f347e67 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ AlgorithmNote ============= Introduction ------------ -AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路和解法的Github Blog,主要对相同和相似的题目的解题思路做归类分析,文中涉及的题目来自Leetcode,微软100题,剑指offer及各大算法博客等。 +AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路和解法,主要对相同和相似的题目的解题思路做归类分析,文中涉及的题目来自Leetcode,微软100题,剑指offer及各大算法博客等。 Chapters ------------ From f01e6fc4fab6ee64004fb48b719b231f2b8b11f1 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 20 Feb 2014 21:51:14 +0800 Subject: [PATCH 018/327] Delete test.md --- test.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test.md diff --git a/test.md b/test.md deleted file mode 100644 index 3b18e51..0000000 --- a/test.md +++ /dev/null @@ -1 +0,0 @@ -hello world From 5b6713665b2450379b86ca4228794f4f34483c9b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 20 Feb 2014 22:24:41 +0800 Subject: [PATCH 019/327] complete Ex1 --- ...3\204\345\220\210|keywords: Permutation, Combination.md" | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" index b80b5e9..638448a 100644 --- "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" +++ "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" @@ -5,7 +5,11 @@ Ex1:[leetcode:next Permutation](http://oj.leetcode.com/problems/next-permutation/) -高效的方法求下一个Permutation。可以这样理解该方法, +高效的方法求下一个Permutation。定义单调递增为最小的序列(如1,2,3,4,5),单调递减为最大的序列(如5,4,3,2,1)。 + +可以这样理解该方法,想象当前数列形成一个开口向下的折线,折线的左半部分单调递增,折线的右半部分单调递减。对于右半单调递减部分(包含顶点),已经没有办法调换其中的数字使得整体数列变大,因为其本身已经是右半部分子序列的最大情形,因此通过交换左半递增部分和右半递减部分来实现,交换的两数为**折线顶点左侧的第一个数x**和**右半递减部分第一个大于x的数y**,这样保证了产生了比原来更大的序列(因为y>x)。为了完成目标,还需要对原右半递减部分进行升序排序,保证产生了恰比原来大的序列(选用了第一个大于x的y且右半部分经过排序成为右半部分的最小序列)。 + +这里可以用倒置右半部分代替排序,原因是y是第一个大于x的数,交换这两个数不会打破右半部分的单调递减特性。 ```cpp void nextPermutation(vector &num) { for(int i = num.size()-1; i>=1; i--){//改变右起的第一个升序对可以使序列变大 From ee80eaf3cfe305f132e33dff0b3f8cd43b6d0475 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 20 Feb 2014 22:54:28 +0800 Subject: [PATCH 020/327] complete Ex2 --- ...210|keywords: Permutation, Combination.md" | 72 ++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" index 638448a..2a36b09 100644 --- "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" +++ "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" @@ -3,9 +3,9 @@ 一般来说有两种解题思路,一种是利用递归生成所有的Permutation,另一种是利用求上一个/下一个Permutation来求出所有的Permutation。该题有可分为有重复和无重复元素的情况。求上一个/下一个的方法适用于有重复和无重复的情况,不需要做适应化修改 而递归方法在有重复元素的情况下需要修改为对当次递归相同的元素做跳过处理。 -Ex1:[leetcode:next Permutation](http://oj.leetcode.com/problems/next-permutation/) +Ex1:[LeetCode:next Permutation](http://oj.leetcode.com/problems/next-permutation/) -高效的方法求下一个Permutation。定义单调递增为最小的序列(如1,2,3,4,5),单调递减为最大的序列(如5,4,3,2,1)。 +高效的方法求下一个Permutation。定义单调递增为最小的序列(如1,2,3,4,5),单调递减为最大的序列(如5,4,3,2,1),序列1,2,3,4,5的下一个Permutation为1,2,3,5,4,序列5,4,3,2,1的下一个Permutation为1,2,3,4,5。 可以这样理解该方法,想象当前数列形成一个开口向下的折线,折线的左半部分单调递增,折线的右半部分单调递减。对于右半单调递减部分(包含顶点),已经没有办法调换其中的数字使得整体数列变大,因为其本身已经是右半部分子序列的最大情形,因此通过交换左半递增部分和右半递减部分来实现,交换的两数为**折线顶点左侧的第一个数x**和**右半递减部分第一个大于x的数y**,这样保证了产生了比原来更大的序列(因为y>x)。为了完成目标,还需要对原右半递减部分进行升序排序,保证产生了恰比原来大的序列(选用了第一个大于x的y且右半部分经过排序成为右半部分的最小序列)。 @@ -26,3 +26,71 @@ void nextPermutation(vector &num) { reverse(num.begin(),num.end());//说明是降序,直接反转为升序为最小的排列 } ``` +Ex2:[LeetCode:Permutation Sequence](http://oj.leetcode.com/problems/permutation-sequence/) + +此题要求寻找给定位数的Permutation的第k个序列,以单调递增序列(如1,2,3,4,5)作为第1个序列。 + +同样应用Ex1中的方法求解,c为长度为n的Permutation总数。为了减少迭代次数,可以看k与c/2的大小关系从两头求解,求上一个Permutation的方法与Ex1类似,详略。 + +**注意点1**:k不一定小于c,需要做mod运算 + +**注意点2**:使用stringstream可以快速将int转换为string +```cpp + string getPermutation(int n, int k) { + string result, temp; + stringstream ss; + int c = 1; + bool isGenerated = false; + + for(int i = 1; i<=n; i++){ + c *= i; + } + k = k % c; + if(k == 0) k = c; + + for(int i = 1; i<=n; i++){ + if(k<=c/2){ + ss<>temp; + result += temp; + ss.clear(); + } + + if(k<=c/2){ + for(int i = 1 ; i < k; i++){//求下一个permutation + isGenerated = false; + for(int j = result.length()-1; j>=1 && !isGenerated; j--){ + if(result[j]>result[j-1]){ + for(int k = result.length()-1; k >= j && !isGenerated; k--){ + if(result[k]>result[j-1]){ + swap(result[k], result[j-1]); + reverse(&result[j],&result[result.length()]); + isGenerated = true; + } + } + } + } + } + }else{ + for(int i = 1 ; i < c-k+1; i++){//求上一个permutation + isGenerated = false; + for(int j = result.length()-1; j>=1 && !isGenerated; j--){ + if(result[j]= j && !isGenerated; k--){ + if(result[k] Date: Fri, 21 Feb 2014 08:40:27 +0800 Subject: [PATCH 021/327] complete Ex3 --- ...210|keywords: Permutation, Combination.md" | 144 +++++++++++------- 1 file changed, 91 insertions(+), 53 deletions(-) diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" index 2a36b09..caba163 100644 --- "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" +++ "b/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" @@ -11,20 +11,23 @@ Ex1:[LeetCode:next Permutation](http://oj.leetcode.com/problems/next-permutation 这里可以用倒置右半部分代替排序,原因是y是第一个大于x的数,交换这两个数不会打破右半部分的单调递减特性。 ```cpp -void nextPermutation(vector &num) { - for(int i = num.size()-1; i>=1; i--){//改变右起的第一个升序对可以使序列变大 - if(num[i]>num[i-1]){//num[i-1]和num[i]是第一个升序对,此时从i到size()-1是降序 - for(int j = num.size()-1; j>=i; j--){ - if(num[j]>num[i-1]){ - swap(num[j], num[i-1]); - reverse(num.begin()+i,num.end()); - return; +class Solution { +public: + void nextPermutation(vector &num) { + for(int i = num.size()-1; i>=1; i--){//改变右起的第一个升序对可以使序列变大 + if(num[i]>num[i-1]){//num[i-1]和num[i]是第一个升序对,此时从i到size()-1是降序 + for(int j = num.size()-1; j>=i; j--){ + if(num[j]>num[i-1]){ + swap(num[j], num[i-1]); + reverse(num.begin()+i,num.end()); + return; + } } } } + reverse(num.begin(),num.end());//说明是降序,直接反转为升序为最小的排列 } - reverse(num.begin(),num.end());//说明是降序,直接反转为升序为最小的排列 -} +}; ``` Ex2:[LeetCode:Permutation Sequence](http://oj.leetcode.com/problems/permutation-sequence/) @@ -36,61 +39,96 @@ Ex2:[LeetCode:Permutation Sequence](http://oj.leetcode.com/problems/permutation- **注意点2**:使用stringstream可以快速将int转换为string ```cpp - string getPermutation(int n, int k) { - string result, temp; - stringstream ss; - int c = 1; - bool isGenerated = false; +class Solution { +public: + string getPermutation(int n, int k) { + string result, temp; + stringstream ss; + int c = 1; + bool isGenerated = false; - for(int i = 1; i<=n; i++){ - c *= i; - } - k = k % c; - if(k == 0) k = c; + for(int i = 1; i<=n; i++){ + c *= i; + } + k = k % c; + if(k == 0) k = c; - for(int i = 1; i<=n; i++){ - if(k<=c/2){ - ss<>temp; + result += temp; + ss.clear(); } - ss>>temp; - result += temp; - ss.clear(); - } - if(k<=c/2){ - for(int i = 1 ; i < k; i++){//求下一个permutation - isGenerated = false; - for(int j = result.length()-1; j>=1 && !isGenerated; j--){ - if(result[j]>result[j-1]){ - for(int k = result.length()-1; k >= j && !isGenerated; k--){ - if(result[k]>result[j-1]){ - swap(result[k], result[j-1]); - reverse(&result[j],&result[result.length()]); - isGenerated = true; + if(k<=c/2){ + for(int i = 1 ; i < k; i++){//求下一个permutation + isGenerated = false; + for(int j = result.length()-1; j>=1 && !isGenerated; j--){ + if(result[j]>result[j-1]){ + for(int k = result.length()-1; k >= j && !isGenerated; k--){ + if(result[k]>result[j-1]){ + swap(result[k], result[j-1]); + reverse(&result[j],&result[result.length()]); + isGenerated = true; + } } } } } - } - }else{ - for(int i = 1 ; i < c-k+1; i++){//求上一个permutation - isGenerated = false; - for(int j = result.length()-1; j>=1 && !isGenerated; j--){ - if(result[j]= j && !isGenerated; k--){ - if(result[k]=1 && !isGenerated; j--){ + if(result[j]= j && !isGenerated; k--){ + if(result[k] > result; + vector > permute(vector &num) { + if(num.size() == 0) return result; + vector temp; + genPermutation(temp, num); + return result; + } + + void genPermutation(vector generated, vector num){ + if(num.empty()){ + result.push_back(generated); + return; + } + generated.push_back(-1); + for(int i = 0; i <= num.size()-1; i++){ + generated.pop_back(); + generated.push_back(num[i]); + swap(num[0], num[i]); + genPermutation(generated, vector(num.begin()+1, num.end())); + } + return; + } +}; ``` From b8dbdac7f509bbc7d850ab490ebc95ae0f77bede Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 08:59:34 +0800 Subject: [PATCH 022/327] complete Ex4 --- ...ions|keywords: Permutation, Combination.md | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) rename "1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" => 1.Permutations and Combinations|keywords: Permutation, Combination.md (79%) diff --git "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" b/1.Permutations and Combinations|keywords: Permutation, Combination.md similarity index 79% rename from "1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" rename to 1.Permutations and Combinations|keywords: Permutation, Combination.md index caba163..b1a95ff 100644 --- "a/1.\346\216\222\345\210\227\344\270\216\347\273\204\345\220\210|keywords: Permutation, Combination.md" +++ b/1.Permutations and Combinations|keywords: Permutation, Combination.md @@ -132,3 +132,45 @@ public: } }; ``` +Ex4:[LeetCode:Permutations II](http://oj.leetcode.com/problems/permutations-ii/) + +与LeetCode:Permutations相比,本题输入可能为有重复的序列,使用求下一个序列的方法仍然可用,此处省略。 + +使用递归方法求解,基本思路与LeetCode:Permutations的递归解法类似,但在同一次递归过程中不能选择大小相等的数,否则会生成重复序列。此处通过始终保持待选数字Vector有序,判断当前数字是否与上一个数字相等来去重。 + +**注意点1**:因为交换后传参,每次进入递归时都要对待选数字Vector排序 + +**注意点2**:选择每个数字后需要再次交换保证待选数字Vector有序 + +```cpp +class Solution { +public: + //recursive + vector > result; + vector > permuteUnique(vector &num) { + if(num.size() == 0) return result; + vector generated; + sort(num.begin(), num.end()); + genPermutation(generated, num); + return result; + } + + void genPermutation(vector generated, vector num){ + if(num.size() == 0){ + result.push_back(generated); + return; + } + sort(num.begin(), num.end()); + generated.push_back(-1); + for(int i = 0; i <= num.size()-1; i++){ + if((i == 0) || num[i] != num[i-1]){ + generated.pop_back(); + generated.push_back(num[i]); + swap(num[0], num[i]); + genPermutation(generated, vector(num.begin()+1, num.end())); + swap(num[0], num[i]); + } + } + } +}; +``` From b98f1e0f056b5c73294f3ea43e36c4cb9232c2e8 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 09:00:59 +0800 Subject: [PATCH 023/327] revise title --- ...tions and Combinations|keywords: Permutation, Combination.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1.Permutations and Combinations|keywords: Permutation, Combination.md b/1.Permutations and Combinations|keywords: Permutation, Combination.md index b1a95ff..1e36226 100644 --- a/1.Permutations and Combinations|keywords: Permutation, Combination.md +++ b/1.Permutations and Combinations|keywords: Permutation, Combination.md @@ -1,4 +1,4 @@ -##1.排列与组合|keywords: Permutation, Combination +##1.Permutations and Combinations|keywords: Permutation, Combination ###*Permutation 一般来说有两种解题思路,一种是利用递归生成所有的Permutation,另一种是利用求上一个/下一个Permutation来求出所有的Permutation。该题有可分为有重复和无重复元素的情况。求上一个/下一个的方法适用于有重复和无重复的情况,不需要做适应化修改 而递归方法在有重复元素的情况下需要修改为对当次递归相同的元素做跳过处理。 From 368483af77f4bc98b0769c46e33bb7bd98130411 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 09:07:27 +0800 Subject: [PATCH 024/327] revise title --- ...ations and Combinations|keywords Permutation, Combination.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename 1.Permutations and Combinations|keywords: Permutation, Combination.md => 1.Permutations and Combinations|keywords Permutation, Combination.md (99%) diff --git a/1.Permutations and Combinations|keywords: Permutation, Combination.md b/1.Permutations and Combinations|keywords Permutation, Combination.md similarity index 99% rename from 1.Permutations and Combinations|keywords: Permutation, Combination.md rename to 1.Permutations and Combinations|keywords Permutation, Combination.md index 1e36226..c526f3e 100644 --- a/1.Permutations and Combinations|keywords: Permutation, Combination.md +++ b/1.Permutations and Combinations|keywords Permutation, Combination.md @@ -1,4 +1,4 @@ -##1.Permutations and Combinations|keywords: Permutation, Combination +##1.Permutations and Combinations|keywords Permutation, Combination ###*Permutation 一般来说有两种解题思路,一种是利用递归生成所有的Permutation,另一种是利用求上一个/下一个Permutation来求出所有的Permutation。该题有可分为有重复和无重复元素的情况。求上一个/下一个的方法适用于有重复和无重复的情况,不需要做适应化修改 而递归方法在有重复元素的情况下需要修改为对当次递归相同的元素做跳过处理。 From a85b0e60fc173899d88f654ca9f26293bd3f1548 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 09:11:52 +0800 Subject: [PATCH 025/327] revise title --- ...ations and Combinations$keywords Permutation, Combination.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename 1.Permutations and Combinations|keywords Permutation, Combination.md => 1.Permutations and Combinations$keywords Permutation, Combination.md (99%) diff --git a/1.Permutations and Combinations|keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md similarity index 99% rename from 1.Permutations and Combinations|keywords Permutation, Combination.md rename to 1.Permutations and Combinations$keywords Permutation, Combination.md index c526f3e..53e9bf4 100644 --- a/1.Permutations and Combinations|keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -1,4 +1,4 @@ -##1.Permutations and Combinations|keywords Permutation, Combination +##1.Permutations and Combinations$keywords Permutation, Combination ###*Permutation 一般来说有两种解题思路,一种是利用递归生成所有的Permutation,另一种是利用求上一个/下一个Permutation来求出所有的Permutation。该题有可分为有重复和无重复元素的情况。求上一个/下一个的方法适用于有重复和无重复的情况,不需要做适应化修改 而递归方法在有重复元素的情况下需要修改为对当次递归相同的元素做跳过处理。 From f5e97e0afb00e7929367648b097b0eaed6ded913 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 09:13:45 +0800 Subject: [PATCH 026/327] revise title --- 2.String dp and Array dp$keywords dp.md | 1 + ...62dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 2.String dp and Array dp$keywords dp.md delete mode 100644 "2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md new file mode 100644 index 0000000..eabb012 --- /dev/null +++ b/2.String dp and Array dp$keywords dp.md @@ -0,0 +1 @@ +##2.String dp and Array dp$keywords dp diff --git "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" "b/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" deleted file mode 100644 index a66b3bf..0000000 --- "a/2.\345\255\227\347\254\246\344\270\262dp\344\270\216\346\225\260\347\273\204dp | keywords: dp.md" +++ /dev/null @@ -1 +0,0 @@ -##2.字符串dp与数组dp | keywords: dp From 85c7b9cc6989c891b72cb831707c3841a0ff841a Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 21 Feb 2014 09:18:16 +0800 Subject: [PATCH 027/327] Build up Image folder --- Image/test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Image/test.txt diff --git a/Image/test.txt b/Image/test.txt new file mode 100644 index 0000000..e69de29 From 3b7eb5d6fa49b73488cbed5d734e86b2eb97578f Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 21 Feb 2014 09:41:43 +0800 Subject: [PATCH 028/327] test image --- Image/QQ1.jpg | Bin 0 -> 20427 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Image/QQ1.jpg diff --git a/Image/QQ1.jpg b/Image/QQ1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65212d611da4928bcc9673042aa9a3e783f09942 GIT binary patch literal 20427 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 GKmXaI1{hNS literal 0 HcmV?d00001 From b4df9793be4f5e7140aaceb3da2b298e86240bca Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 21 Feb 2014 09:58:00 +0800 Subject: [PATCH 029/327] remove test.txt --- Image/test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Image/test.txt diff --git a/Image/test.txt b/Image/test.txt deleted file mode 100644 index e69de29..0000000 From fec86268382ea87c42c21fa480582a05268cd3f2 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 10:20:36 +0800 Subject: [PATCH 030/327] complete Ex5 --- ...tions$keywords Permutation, Combination.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index 53e9bf4..b3f9c0f 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -174,3 +174,56 @@ public: } }; ``` + +###*Combination +对于Combination通常的解法是递归,与Permutation不同的地方在于每个递归过程只需考虑是否选当前数字,这是Combination的位置无关导致。 + +Ex5:[LeetCode:Combinations](http://oj.leetcode.com/problems/combinations/) + +该题要求求出1...n的长度为k的组合结果集合,很容易想到递归,对于每个数都有选与不选两种选择,使用一个Stack(此处用Vecotr模拟)记录已选组合。 +```cpp +class Solution { +public: + vector > result; + vector > combine(int n, int k) { + // IMPORTANT: Please reset any member data you declared, as + // the same Solution instance will be reused for each test case. + if(n <= 0 || k <= 0) return result; + vector temp; + temp.clear(); + k = k % n; + if(k == 0) k = n; + genCombination(temp,1, n, k); + return result; + } + + void genCombination(vector& temp, int start, int end, int k){ + //比较正统的办法,每次递归都有两个选择:选或不选 + if(k == 0){ + result.push_back(temp); + return; + } + if(start>end) return; + //if(end-start+1& temp, int start, int end, int k){ + //一个较为取巧的办法,利用结果的单调性,给下一次递归传i+1,循环的过程实际上替代了不选某(或某些)数的递归过程 + if(k == 0){ + result.push_back(temp); + return; + } + //if(end-start+1 Date: Fri, 21 Feb 2014 11:13:22 +0800 Subject: [PATCH 031/327] complete Ex6 --- ...tions$keywords Permutation, Combination.md | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index b3f9c0f..fceb41a 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -134,7 +134,7 @@ public: ``` Ex4:[LeetCode:Permutations II](http://oj.leetcode.com/problems/permutations-ii/) -与LeetCode:Permutations相比,本题输入可能为有重复的序列,使用求下一个序列的方法仍然可用,此处省略。 +与Ex3相比,本题输入可能为有重复的序列,使用求下一个序列的方法仍然可用,此处省略。 使用递归方法求解,基本思路与LeetCode:Permutations的递归解法类似,但在同一次递归过程中不能选择大小相等的数,否则会生成重复序列。此处通过始终保持待选数字Vector有序,判断当前数字是否与上一个数字相等来去重。 @@ -227,3 +227,41 @@ public: }*/ }; ``` + +Ex6:[LeetCode:Combination Sum](http://oj.leetcode.com/problems/combination-sum/) + +此题要求一定条件下的组合数,思路与Ex5类似,只不过对于每个数有不选,选1,选2个...选n个共n+1个选择,注意剪枝。使用set去重,暂时没考虑在求解过程中自动去重(对candidates排序,看当前数字和前一个数字是否相同进行去重可能可行)。 +```cpp +class Solution { +public: + set > resultSet; + vector > combinationSum(vector &candidates, int target) { + vector > result; + vector temp; + if(candidates.size() == 0) return result; + sort(candidates.begin(),candidates.end()); + compute(temp, candidates, 0, 0, target); + for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ + result.push_back(*itr); + } + return result; + } + + void compute(vector temp, vector& candidates, int index, int currentVal, int target){ + if(index == candidates.size()) return; + + compute(temp, candidates, index+1, currentVal, target); + + for(int i = 1; currentVal + i * candidates[index] <= target; i++){ + temp.push_back(candidates[index]); + if(currentVal + i * candidates[index] == target){ + resultSet.insert(temp); + }else{ + compute(temp, candidates, index+1, currentVal+i*candidates[index], target); + } + } + + return; + } +}; +``` From 9290782b22a493b9b7ac3c21c007db1f74d1a653 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 11:28:07 +0800 Subject: [PATCH 032/327] complete Ex7 --- ...tions$keywords Permutation, Combination.md | 86 ++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index fceb41a..f81a4a7 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -230,7 +230,7 @@ public: Ex6:[LeetCode:Combination Sum](http://oj.leetcode.com/problems/combination-sum/) -此题要求一定条件下的组合数,思路与Ex5类似,只不过对于每个数有不选,选1,选2个...选n个共n+1个选择,注意剪枝。使用set去重,暂时没考虑在求解过程中自动去重(对candidates排序,看当前数字和前一个数字是否相同进行去重可能可行)。 +此题要求一定条件下的组合数,思路与Ex5类似,只不过对于每个数有不选,选1,选2个...选n个共n+1个选择,注意剪枝。使用Set去重,暂时没考虑在求解过程中自动去重(对candidates排序,看当前数字和前一个数字是否相同进行去重可能可行)。 ```cpp class Solution { public: @@ -265,3 +265,87 @@ public: } }; ``` + +Ex7:[LeetCode:Combination Sum II](http://oj.leetcode.com/problems/combination-sum-ii/) + +此题与Ex6区别在于每个数只能用一次,该问题更确切的说是一个01背包问题,使用Set去重,应用以下剪枝方法需要对待选数字升序排序。 + +01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k!=M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 +**选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk+Σ(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 +**不选择k**:若t+r-k>=M&&t+(k+1)<=M,一方面判断剩下的物品还足够填满M,同时同选择k情形判断第k+1个物品是否使得X的解可能存在。 + +```cpp +class Solution { +public: + + set > resultSet; + vector > combinationSum2(vector &num, int target) { + vector > result; + if(num.size() == 0) return result; + vector temp; + temp.clear(); + sort(num.begin(), num.end()); + int rest = 0; + for(int i = 0; i<=num.size()-1; i++){ + rest += num[i]; + } + compute(temp, num, 0, rest, target); + for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ + result.push_back(*itr); + } + + return result; + } + + + //优化剪枝的递归函数 92ms + void compute(vector& temp, vector num, int currentVal, int restVal, int target){ + if(num.size() == 0) return; + + if(currentVal + num[0] == target){ + temp.push_back(num[0]); + resultSet.insert(temp); + temp.pop_back(); + return; + } + + if(num.size() == 1) return; + + if(currentVal + num[0] + num[1] <= target){ + temp.push_back(num[0]); + compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); + temp.pop_back(); + } + + if(currentVal + restVal - num[0] >= target && currentVal + num[1] <= target){ + compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); + } + + return; + } + + + //未优化剪枝的递归函数 1160ms + /* + void compute(vector& temp, vector num, int currentVal, int restVal, int target){ + if(num.size() == 0) return; + + if(currentVal + num[0] == target){ + temp.push_back(num[0]); + resultSet.insert(temp); + temp.pop_back(); + return; + } + + if(currentVal + num[0] <= target){ + temp.push_back(num[0]); + compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); + temp.pop_back(); + } + + compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); + + return; + }*/ +}; +``` From 352f2187b893729d703e7f117577128adc535edd Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 11:31:13 +0800 Subject: [PATCH 033/327] Update 1.Permutations and Combinations$keywords Permutation, Combination.md --- ...ations and Combinations$keywords Permutation, Combination.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index f81a4a7..35e2c17 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -271,7 +271,9 @@ Ex7:[LeetCode:Combination Sum II](http://oj.leetcode.com/problems/combination-su 此题与Ex6区别在于每个数只能用一次,该问题更确切的说是一个01背包问题,使用Set去重,应用以下剪枝方法需要对待选数字升序排序。 01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k!=M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 + **选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk+Σ(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 + **不选择k**:若t+r-k>=M&&t+(k+1)<=M,一方面判断剩下的物品还足够填满M,同时同选择k情形判断第k+1个物品是否使得X的解可能存在。 ```cpp From e670a490c843d9465a585ded5bf9179e067ddcb7 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 11:33:27 +0800 Subject: [PATCH 034/327] complete Ex8 --- ...tions$keywords Permutation, Combination.md | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index 35e2c17..659620d 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -351,3 +351,78 @@ public: }*/ }; ``` + +Ex8:[LeetCode:Letter Combinations of a Phone Number ](http://oj.leetcode.com/problems/letter-combinations-of-a-phone-number/) + +递归方法,做好映射,对每个数字的可能情况进行递归。 + +```cpp +class Solution { +public: + vector result; + vector letterCombinations(string digits) { + string temp; + recursion(digits, temp, 0); + return result; + } + + void recursion(string &digits, string temp, int index){ + if(index == digits.size()){ + result.push_back(temp); + } + vector charV = toChar(digits[index]-'0'); + for(vector::iterator itr = charV.begin(); itr != charV.end(); itr++){ + recursion(digits, temp+(*itr), index+1); + } + } + + vector toChar(int i){ + vector result; + switch(i){ + case 2: + result.push_back('a'); + result.push_back('b'); + result.push_back('c'); + break; + case 3: + result.push_back('d'); + result.push_back('e'); + result.push_back('f'); + break; + case 4: + result.push_back('g'); + result.push_back('h'); + result.push_back('i'); + break; + case 5: + result.push_back('j'); + result.push_back('k'); + result.push_back('l'); + break; + case 6: + result.push_back('m'); + result.push_back('n'); + result.push_back('o'); + break; + case 7: + result.push_back('p'); + result.push_back('q'); + result.push_back('r'); + result.push_back('s'); + break; + case 8: + result.push_back('t'); + result.push_back('u'); + result.push_back('v'); + break; + case 9: + result.push_back('w'); + result.push_back('x'); + result.push_back('y'); + result.push_back('z'); + break; + } + return result; + } +}; +``` From e9eb335d672d54668f3c6cec051a18c1c17001b1 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 14:06:53 +0800 Subject: [PATCH 035/327] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f347e67..d7bbb72 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ -1.排列与组合|keywords: Permutation, Combination -2.字符串dp与数组dp | keywords: dp +1.Permutations and Combinations$keywords Permutation, Combination +2.String dp and array dp$keywords: dp Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From d53d880f004f2fc6312111c8e9ad1b163198be8b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 14:12:47 +0800 Subject: [PATCH 036/327] Update 1.Permutations and Combinations$keywords Permutation, Combination.md --- ...ations and Combinations$keywords Permutation, Combination.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index 659620d..b2faa15 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -176,7 +176,7 @@ public: ``` ###*Combination -对于Combination通常的解法是递归,与Permutation不同的地方在于每个递归过程只需考虑是否选当前数字,这是Combination的位置无关导致。 +对于Combination通常的解法是递归,与Permutation不同的地方在于每个递归过程只需考虑是否选当前数字,这是Combination由位置无关特性决定的。 Ex5:[LeetCode:Combinations](http://oj.leetcode.com/problems/combinations/) From 6474e4c7a1e0924e919cc377b877d4f093a8ac12 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 16:41:47 +0800 Subject: [PATCH 037/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 56 ++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index eabb012..d0fafd5 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -1 +1,55 @@ -##2.String dp and Array dp$keywords dp +##2.String dp and Array dp$keywords dp +###*String dp +dp有几种用途,其中之一就是标记 +Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/) +该题dp的作用就是标记,使用二维dp[i][j]来表示i j之间是否有继续搜索的必要,即是否可以将i j之间的串切成回文 +标记是在搜索之前判断的,之后就可dps来搜索 +```java +import java.util.ArrayList; +import java.util.HashSet; + +public class Solution { + public ArrayList> partition(String s) { + HashSet> set = new HashSet>(); + ArrayList tmp = new ArrayList(); + visit(s, tmp, set); + + return new ArrayList>(set); + } + + public void visit(String s, ArrayList tmp, + HashSet> set) { + // System.out.println(s); + if (s == null || s.equals("")) { + // System.out.println(tmp.get(0)); + set.add(new ArrayList(tmp)); + return; + } + for (int i = 0; i < s.length(); i++) { + String t = s.substring(0, i + 1); + if (isPalin(t)) { + // System.out.println(t); + tmp.add(t); + visit(s.substring(i + 1), tmp, set); + tmp.remove(tmp.size() - 1); + } + } + } + + public boolean isPalin(String t) { + for (int i = 0; i < t.length() / 2; i++) { + if (t.charAt(i) != t.charAt(t.length() - 1 - i)) + return false; + } + return true; + } + + public static void main(String[] args) { + Solution t = new Solution(); + String s = "a"; + t.partition(s); + } +} +``` +dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下表i j,而有可能是从0到某个最大值,或者从0到某个最大和 +Ex2:[Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) From 2801fde826eb7e501daec18af96cbd6972695ebc Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 16:48:40 +0800 Subject: [PATCH 038/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 78 +++++++++++++++---------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index d0fafd5..c0ff1d6 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -3,53 +3,67 @@ dp有几种用途,其中之一就是标记 Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/) 该题dp的作用就是标记,使用二维dp[i][j]来表示i j之间是否有继续搜索的必要,即是否可以将i j之间的串切成回文 -标记是在搜索之前判断的,之后就可dps来搜索 +标记是在搜索之前判断的,之后就可dfs来搜索 ```java -import java.util.ArrayList; -import java.util.HashSet; - public class Solution { + ArrayList> all = new ArrayList>(); + public ArrayList> partition(String s) { - HashSet> set = new HashSet>(); - ArrayList tmp = new ArrayList(); - visit(s, tmp, set); + all.clear(); + int length = s.length(); + boolean[][] seg = new boolean[length][length + 1]; + for (int len = 1; len <= length; len++) { + for (int i = 0; i < length - len + 1; i++) { + String t = s.substring(i, i + len); + if (isPalindrome(t)) { + seg[i][len] = true; + continue; + } + for (int k = 1; k < len; k++) { + if (seg[i][k] && seg[i + k][len - k]) { + seg[i][len] = true; + break; + } + } + } + } - return new ArrayList>(set); + part(s, seg, 0, 0, new ArrayList()); + return all; } - public void visit(String s, ArrayList tmp, - HashSet> set) { - // System.out.println(s); - if (s == null || s.equals("")) { - // System.out.println(tmp.get(0)); - set.add(new ArrayList(tmp)); + public void part(String s, boolean[][] seg, int start, int depth, + ArrayList list) { + int length = s.length(); + if (depth == length) { + ArrayList listCopy = new ArrayList(list); + all.add(listCopy); + return; } - for (int i = 0; i < s.length(); i++) { - String t = s.substring(0, i + 1); - if (isPalin(t)) { - // System.out.println(t); - tmp.add(t); - visit(s.substring(i + 1), tmp, set); - tmp.remove(tmp.size() - 1); + for (int len = 1; len <= length; len++) { + if (seg[start][len]) { + String word = s.substring(start, start + len); + // System.out.println(word); + if (isPalindrome(word)) { + // System.out.println(start + " " + start + len); + list.add(word); + part(s, seg, start + len, start + len, list); + list.remove(list.size() - 1); + } } } + } - public boolean isPalin(String t) { - for (int i = 0; i < t.length() / 2; i++) { - if (t.charAt(i) != t.charAt(t.length() - 1 - i)) + public boolean isPalindrome(String s) { + for (int i = 0; i < s.length() / 2; i++) + if (s.charAt(i) != s.charAt(s.length() - i - 1)) return false; - } return true; } - - public static void main(String[] args) { - Solution t = new Solution(); - String s = "a"; - t.partition(s); - } } ``` -dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下表i j,而有可能是从0到某个最大值,或者从0到某个最大和 +dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 Ex2:[Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) +此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 From ed30e8a2b3269ae2ba762cfdaef986e421738359 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 17:05:33 +0800 Subject: [PATCH 039/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 51 ++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index c0ff1d6..1c0f29d 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -2,7 +2,7 @@ ###*String dp dp有几种用途,其中之一就是标记 Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/) -该题dp的作用就是标记,使用二维dp[i][j]来表示i j之间是否有继续搜索的必要,即是否可以将i j之间的串切成回文 +该题dp的作用就是标记和剪枝,使用二维dp[i][len]来表示i i+len-1之间是否有继续搜索的必要,即是否可以将i i+len-1之间的串切成回文。 标记是在搜索之前判断的,之后就可dfs来搜索 ```java public class Solution { @@ -46,7 +46,6 @@ public class Solution { String word = s.substring(start, start + len); // System.out.println(word); if (isPalindrome(word)) { - // System.out.println(start + " " + start + len); list.add(word); part(s, seg, start + len, start + len, list); list.remove(list.size() - 1); @@ -67,3 +66,51 @@ public class Solution { dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 Ex2:[Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) 此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 +若s3的i+j-1串已经和s1的i串与s2的j-1串匹配,此时若s2的第j-1个字符和s3的第i+j-1个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配 +```java +public class Solution { + public boolean isInterleave(String s1, String s2, String s3) { + if (s3.length() != s1.length() + s2.length()) + return false; + if (s1.length() == 0) + if (!s2.equals(s3)) + return false; + else + return true; + if (s2.length() == 0) + if (!s1.equals(s3)) + return false; + else + return true; + boolean[][] dp = new boolean[s1.length() + 1][s2.length() + 1]; + dp[0][0] = true; + + for (int i = 1; i <= s1.length(); i++) + if (dp[i - 1][0] && s1.charAt(i - 1) == s3.charAt(i - 1)) + dp[i][0] = true; + + for (int j = 1; j <= s2.length(); j++) + if (dp[0][j - 1] && s2.charAt(j - 1) == s3.charAt(j - 1)) + dp[0][j] = true; + + for (int i = 1; i <= s1.length(); i++) + for (int j = 1; j <= s2.length(); j++) { + if (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) + dp[i][j] = true; + if (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1)) + dp[i][j] = true; + } + + return dp[s1.length()][s2.length()]; + } + + public static void main(String[] args) { + Solution m = new Solution(); + String s1 = "aabccabc"; + String s2 = "dbbabc"; + String s3 = "aabdbbccababcc"; + boolean result = m.isInterleave(s1, s2, s3); + System.out.print(result); + } +} +``` From 5dc6dff70237ce791847fb7a29e9b5257d272f4b Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 17:28:26 +0800 Subject: [PATCH 040/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 1c0f29d..e30882d 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -114,3 +114,35 @@ public class Solution { } } ``` +Ex3:[Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) +又是一道字符串匹配的题。这道题dp[j][i]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] +```cpp +class Solution { +public: + + bool isMatch(const char *s, const char *p) { + int len_s = strlen(s); + int len_p = strlen(p); + + const char* tmp = p; + int cnt = 0; + while (*tmp != '\0') if (*(tmp++) != '*') cnt++; + if (cnt > len_s) return false; + + bool dp[500][500]; + memset(dp, 0,sizeof(dp)); + + dp[0][0] = true; + for (int i = 1; i <= len_p; i++) { + if (dp[0][i-1] && p[i-1] == '*') dp[0][i] = true; + for (int j = 1; j <= len_s; ++j) + { + if (p[i-1] == '*') dp[j][i] = (dp[j-1][i] || dp[j][i-1]); + else if (p[i-1] == '?' || p[i-1] == s[j-1]) dp[j][i] = dp[j-1][i-1]; + else dp[j][i] = false; + } + } + return dp[len_s][len_p]; + } +}; +``` From a018dd28fdea62969af242242d4bc95347bd370f Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 17:55:09 +0800 Subject: [PATCH 041/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index e30882d..bb32607 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -146,3 +146,42 @@ public: } }; ``` +Ex4:[Edit Distance](http://oj.leetcode.com/problems/edit-distance/) +两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 +```java +public class Solution { + public int minDistance(String word1, String word2) { + if (word1.length() == 0) + return word2.length(); + if (word2.length() == 0) + return word1.length(); + int[][] dp = new int[word1.length()][word2.length()]; + int result = search(0, 0, word1, word2, dp); + return result; + } + + public int search(int i, int j, String s1, String s2, int[][] dp) { + if (i == s1.length()) + return s2.length() - j; + if (j == s2.length()) + return s1.length() - i; + if (dp[i][j] != 0) + return dp[i][j]; + if (s1.charAt(i) == s2.charAt(j)) { + int tmp = search(i + 1, j + 1, s1, s2, dp); + dp[i][j] = tmp; + return tmp; + } + int tmp1 = search(i, j + 1, s1, s2, dp) + 1; + int tmp2 = search(i + 1, j, s1, s2, dp) + 1; + int tmp3 = search(i + 1, j + 1, s1, s2, dp) + 1; + int result = tmp1; + if (result > tmp2) + result = tmp2; + if (result > tmp3) + result = tmp3; + dp[i][j] = result; + return result; + } +} +``` From 03686158bad2e0c27f82c84102ad1c072c4a2834 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 17:57:34 +0800 Subject: [PATCH 042/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index bb32607..6acfb61 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -64,7 +64,7 @@ public class Solution { } ``` dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 -Ex2:[Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) +Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) 此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 若s3的i+j-1串已经和s1的i串与s2的j-1串匹配,此时若s2的第j-1个字符和s3的第i+j-1个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配 ```java @@ -114,7 +114,7 @@ public class Solution { } } ``` -Ex3:[Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) +Ex3:[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) 又是一道字符串匹配的题。这道题dp[j][i]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] ```cpp class Solution { @@ -146,7 +146,7 @@ public: } }; ``` -Ex4:[Edit Distance](http://oj.leetcode.com/problems/edit-distance/) +Ex4:[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/) 两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 ```java public class Solution { From b1978343dc02d68a0322a40f5731090cf36cac2a Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 18:02:13 +0800 Subject: [PATCH 043/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 6acfb61..5791275 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -1,6 +1,6 @@ ##2.String dp and Array dp$keywords dp ###*String dp -dp有几种用途,其中之一就是标记 +dp有几种用途,其中之一就是标记和剪枝 Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/) 该题dp的作用就是标记和剪枝,使用二维dp[i][len]来表示i i+len-1之间是否有继续搜索的必要,即是否可以将i i+len-1之间的串切成回文。 标记是在搜索之前判断的,之后就可dfs来搜索 @@ -66,7 +66,7 @@ public class Solution { dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) 此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 -若s3的i+j-1串已经和s1的i串与s2的j-1串匹配,此时若s2的第j-1个字符和s3的第i+j-1个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配 +若s3的i+j-1串已经和s1的i串与s2的j-1串匹配,此时若s2的第j-1个字符和s3的第i+j-1个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配。s1的i-1加s2的j同理 ```java public class Solution { public boolean isInterleave(String s1, String s2, String s3) { @@ -146,7 +146,7 @@ public: } }; ``` -Ex4:[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/) +Ex4:[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/) 两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 ```java public class Solution { From b51f7ef2e59052f21810080af15775ef8919e7e2 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 18:46:07 +0800 Subject: [PATCH 044/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 64 ++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 5791275..688c65f 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -184,4 +184,66 @@ public class Solution { return result; } } -``` +``` +###*Array dp +Ex5:最长公共子序列(LCS):举个例子,如:有两条随机序列,如 1 3 4 5 5 ,and 2 4 5 5 7 6,则它们的最长公共子序列便是:4 5 5。并打印出最长子序列 +经典的动态规划问题。dp[i][j]表示p1的前i的个字符和p2的前j个字符匹配的最大长度。定位到dp[i][j]。若p1中的第i个字符与p2的第j个字符相等,则dp[i][j]=dp[i-1][j-1]+1;若不相等,则为dp[i-1][j]和dp[i][j-1]中较大的一个。关键问题是如何打印最长公共子序列。这里我们可以再使用一个二维数组route来标记当前的状态是从哪一个状态得来。route[i][j]有三个值,分别为1 2 3,1表示由dp[i-1][j]得来,2表示由dp[i-1][j-1]得来,3表示由dp[i][j-1]得来。当得到最长公共子序列的长度后,dp[p1.length()-1][p2.length()-1]开始向前查找,route[i][j]为1 i--,为3 j--,为2 i-- j--并将当前值填入结果数组。最后将数组逆序输出即可。 +```java +import java.util.ArrayList; + +public class MyOwn { + public void LCS(char[] a, char[] b) { + int len1 = a.length; + int len2 = b.length; + int[][] dp = new int[len1 + 1][len2 + 1]; + char[][] mark = new char[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) + dp[i][0] = 0; + for (int i = 0; i <= len2; i++) + dp[0][i] = 0; + for (int i = 1; i <= len1; i++) + for (int j = 1; j <= len2; j++) { + if (a[i - 1] == b[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + mark[i][j] = '2'; + } else { + if (dp[i][j - 1] >= dp[i - 1][j]) { + dp[i][j] = dp[i][j - 1]; + mark[i][j] = '3'; + } else { + dp[i][j] = dp[i - 1][j]; + mark[i][j] = '1'; + } + } + } + + System.out.println(dp[len1][len2]); + ArrayList l = new ArrayList(); + int i = len1; + int j = len2; + while (i >= 0 && j >= 0) { + if (mark[i][j] == '1') + i--; + + else if (mark[i][j] == '3') + j--; + + else { + l.add(i); + i--; + j--; + } + } + for (i = l.size() - 1; i >= 0; i--) + System.out.print(a[l.get(i)] + " "); + } + + public static void main(String[] args) { + MyOwn m = new MyOwn(); + char[] a = { 'c', 'n', 'b', 'l', 'o', 'g', 's' }; + char[] b = { 'b', 'e', 'l', 'o', 'n', 'g' }; + m.LCS(a, b); + } +} +``` From 49a4d27ee8a67e47d905037d24042933f4649449 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 18:52:16 +0800 Subject: [PATCH 045/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 688c65f..32017cf 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -186,7 +186,7 @@ public class Solution { } ``` ###*Array dp -Ex5:最长公共子序列(LCS):举个例子,如:有两条随机序列,如 1 3 4 5 5 ,and 2 4 5 5 7 6,则它们的最长公共子序列便是:4 5 5。并打印出最长子序列 +Ex5:最长公共子序列(LCS):请编写一个函数,输入两个字符串,求它们的最长公共子序列,并打印出最长公共子序列。 经典的动态规划问题。dp[i][j]表示p1的前i的个字符和p2的前j个字符匹配的最大长度。定位到dp[i][j]。若p1中的第i个字符与p2的第j个字符相等,则dp[i][j]=dp[i-1][j-1]+1;若不相等,则为dp[i-1][j]和dp[i][j-1]中较大的一个。关键问题是如何打印最长公共子序列。这里我们可以再使用一个二维数组route来标记当前的状态是从哪一个状态得来。route[i][j]有三个值,分别为1 2 3,1表示由dp[i-1][j]得来,2表示由dp[i-1][j-1]得来,3表示由dp[i][j-1]得来。当得到最长公共子序列的长度后,dp[p1.length()-1][p2.length()-1]开始向前查找,route[i][j]为1 i--,为3 j--,为2 i-- j--并将当前值填入结果数组。最后将数组逆序输出即可。 ```java import java.util.ArrayList; From c1ed5c4f97fb0d2e3115f2f3366297537f819c2f Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 18:55:49 +0800 Subject: [PATCH 046/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 32017cf..924a7e2 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -1,7 +1,9 @@ ##2.String dp and Array dp$keywords dp ###*String dp dp有几种用途,其中之一就是标记和剪枝 + Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/) + 该题dp的作用就是标记和剪枝,使用二维dp[i][len]来表示i i+len-1之间是否有继续搜索的必要,即是否可以将i i+len-1之间的串切成回文。 标记是在搜索之前判断的,之后就可dfs来搜索 ```java @@ -64,7 +66,9 @@ public class Solution { } ``` dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 + Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) + 此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 若s3的i+j-1串已经和s1的i串与s2的j-1串匹配,此时若s2的第j-1个字符和s3的第i+j-1个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配。s1的i-1加s2的j同理 ```java @@ -114,7 +118,9 @@ public class Solution { } } ``` + Ex3:[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) + 又是一道字符串匹配的题。这道题dp[j][i]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] ```cpp class Solution { @@ -146,7 +152,9 @@ public: } }; ``` + Ex4:[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/) + 两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 ```java public class Solution { @@ -185,8 +193,11 @@ public class Solution { } } ``` + ###*Array dp -Ex5:最长公共子序列(LCS):请编写一个函数,输入两个字符串,求它们的最长公共子序列,并打印出最长公共子序列。 + +Ex5:最长公共子序列(LCS):请编写一个函数,输入两个字符串,求它们的最长公共子序列长度,并打印出最长公共子序列。 + 经典的动态规划问题。dp[i][j]表示p1的前i的个字符和p2的前j个字符匹配的最大长度。定位到dp[i][j]。若p1中的第i个字符与p2的第j个字符相等,则dp[i][j]=dp[i-1][j-1]+1;若不相等,则为dp[i-1][j]和dp[i][j-1]中较大的一个。关键问题是如何打印最长公共子序列。这里我们可以再使用一个二维数组route来标记当前的状态是从哪一个状态得来。route[i][j]有三个值,分别为1 2 3,1表示由dp[i-1][j]得来,2表示由dp[i-1][j-1]得来,3表示由dp[i][j-1]得来。当得到最长公共子序列的长度后,dp[p1.length()-1][p2.length()-1]开始向前查找,route[i][j]为1 i--,为3 j--,为2 i-- j--并将当前值填入结果数组。最后将数组逆序输出即可。 ```java import java.util.ArrayList; From 29bd1215281549ef5766ed2393ca87a9c050fc07 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 19:16:49 +0800 Subject: [PATCH 047/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 924a7e2..7ac01a8 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -258,3 +258,47 @@ public class MyOwn { } } ``` + +Ex6:最长上升子序列(LIS):给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s12,所以序列长度加一,最后一位为3,3<4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 +```java +import java.util.ArrayList; + +public class MyOwn1 { + public void LIS(int[] a) { + int len = a.length; + int[] b = new int[len + 1]; + b[1] = a[0]; + int max = 1; + ArrayList result = new ArrayList(); + for (int i = 1; i < len; i++) { + int start = 1; + int end = max; + while (start <= end) { + int middle = (start + end) / 2; + if (b[middle] < a[i]) + start = middle + 1; + else if (b[middle] > a[i]) + end = middle - 1; + } + b[start] = a[i]; + if (start > max) { + max++; + result.clear(); + for (int j = 1; j <= max; j++) + result.add(b[j]); + } + } + System.out.println("result: " + max); + System.out.println(result); + } + + public static void main(String[] args) { + MyOwn1 m = new MyOwn1(); + int[] a = { 2, 1, 5, 3, 6, 4, 8, 9, 7 }; + m.LIS(a); + } +} +``` From 4be328bb4390c063d4f28bd48e5feffeb17bc9c6 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 19:20:01 +0800 Subject: [PATCH 048/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 7ac01a8..97c203e 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -262,7 +262,7 @@ public class MyOwn { Ex6:最长上升子序列(LIS):给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s12,所以序列长度加一,最后一位为3,3<4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 +=j表示长度为i的递增子序列的最后一个数是j。在对原数组遍历的过程中,每一次都要将a[i]更新到dp的对应位置去。比如a[4]=3,而dp[1]=2,dp[2]=4,表示长度为1的递增子序列最后一个数是2,长度为2的递增子序列最后一个数是4,此时就可以将dp[2]更新为3,。因为长度为1的递增子序列最后一位为2,3>2,所以序列长度加一,最后一位为3,3<4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 ```java import java.util.ArrayList; From 8bcf1b518e4f289ebb0d4b27de9a2f7dcacd7a07 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 20:44:06 +0800 Subject: [PATCH 049/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 97c203e..d6afd89 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -70,7 +70,7 @@ dp的作用其二,记录状态。一般记录int状态或boolean状态,下 Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) 此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 -若s3的i+j-1串已经和s1的i串与s2的j-1串匹配,此时若s2的第j-1个字符和s3的第i+j-1个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配。s1的i-1加s2的j同理 +若s3的前i+j-1串已经和s1的前i串与s2的前j-1串匹配,此时若s2的第j个字符和s3的第i+j个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配。s1的i-1加s2的j同理 ```java public class Solution { public boolean isInterleave(String s1, String s2, String s3) { @@ -262,7 +262,7 @@ public class MyOwn { Ex6:最长上升子序列(LIS):给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s12,所以序列长度加一,最后一位为3,3<4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 +=j表示长度为i的递增子序列的最后一个数是j。在对原数组遍历的过程中,每一次都要将a[i]更新到dp的对应位置去。比如a[4]=3,而dp[1]=2,dp[2]=4,表示长度为1的递增子序列最后一个数是2,长度为2的递增子序列最后一个数是4,此时就可以将dp[2]更新为3,因为长度为1的递增子序列最后一位为2,3>2,所以序列长度加一,最后一位为3,3<4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 ```java import java.util.ArrayList; From 54676362ef6b5d96fe402a806497e978b5c2a035 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 21:46:05 +0800 Subject: [PATCH 050/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 55 +++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index d6afd89..9f5934c 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -302,3 +302,58 @@ public class MyOwn1 { } } ``` + +Ex7:将数组分成元素个数相等,和最接近的两部分,求和的较大值 + +dp可以有两种状态,boolean和int,这两种方法都可以用来解决这道题。 +首先看int dp。二维dp[i][j]中,i和j不再表示数组下标。dp[i][j]表示取i件物品,总和不超过j的最大值是多少。关注dp[i][j]。遍历到某一件物品k,若状态dp[i-1][j-a[k]]=m(表示可以到达该状态),则dp[i][j]可以为m+a[k],但我们并不能确定dp[i][j]为最大值,因为可能已经通过别的方式到达dp[i][j],所以dp[i][j]=max(dp[i-1][j-a[k]]+a[k],dp[i][j]),表示这第k件物品可加可不加。 +再看boolean dp。dp[i][j]表示是否可以找到i个数,使他们的和等于j。依旧关注dp[i][j]。对于一件物品k,若状态dp[i-1][j-a[k]]可达到,则dp[i][j]可达到。 + +```java + +public class Solution { + int arr[] = { 0, 1, 5, 7, 8, 9, 6, 3, 11, 20, 17 }; + int N = 5; + int SUM = 87; + + int solve2() { + int i, j, s; + int[][] dp = new int[N + 1][SUM / 2 + 2]; // 取N+1件物品,总合不超过SUM/2+2,的最大值是多少 + + for (i = 1; i <= 2 * N; ++i) { + // for (j = 1; j <= Math.min(i, N); ++j) { + for (j = 1; j <= N; ++j) { + for (s = SUM / 2 + 1; s >= arr[i]; --s) // 01背包从大到小,可以省空间,即最外层的空间 + { + dp[j][s] = Math.max(dp[j - 1][s - arr[i]] + arr[i], + dp[j][s]); + } + } + } + i = N; + int t = SUM / 2 + 1; + return dp[N][SUM / 2 + 1]; + } + + int solve3() { + int i, j, s; + int[][] isOK = new int[N + 1][SUM / 2 + 2]; // isOK[i][v]表示是否可以找到i个数,使得它们之和等于v + // 注意初始化 + isOK[0][0] = 1; // 可以,取0件物品,总合为0,是合法的 + + for (i = 1; i <= 2 * N; ++i) { + for (j = 1; j <= Math.min(i, N); ++j) { + for (s = SUM / 2 + 1; s >= arr[i]; --s) // 从大到小,数组少了一维 + { + if (isOK[j - 1][s - arr[i]] == 1) + isOK[j][s] = 1; + } + } + } + for (s = SUM / 2 + 1; s >= 0; --s) { + if (isOK[N][s] == 1) + return s; + } + return 0; + } +} From fd71fd10e5212fbeeaa46d4ac17f646978a05ca1 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 22:07:30 +0800 Subject: [PATCH 051/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 9f5934c..33875ed 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -357,3 +357,6 @@ public class Solution { return 0; } } + +Ex8:求随机数构成的数组中最长的等差数列, 输出等差数列由小到大 +这道题的dp[i][j]就更有点神奇了,dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢? From 38649b13a2e75b829aa0fcd6b819b080f3292d77 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 22:15:27 +0800 Subject: [PATCH 052/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 48 ++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 33875ed..86324ca 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -357,6 +357,52 @@ public class Solution { return 0; } } +``` Ex8:求随机数构成的数组中最长的等差数列, 输出等差数列由小到大 -这道题的dp[i][j]就更有点神奇了,dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢? +这道题的dp[i][j]就更有点神奇了,dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢?j是等差之差,i是最后一个元素。如果能有a[i]-a[t]=j的话,那么dp[t][j]就应该能达到dp[i][j],并且dp[i][j]有可能等于dp[t][j]+1,因为和之前题目中的原因一样,有可能这个状态在之前已经被遍历过了,有更大的值,所以dp[i][j]=max(dp[t][j]+1,dp[i][j])。又,如果dp[i][j]大于我们记录的等差数列长度的最大值,则更新等差数列长度最大值,同时记录等差数列最后一个元素,等差之差。有了这三个元素就可以推出整个等差数列的元素。 + +```java +public class MyOwn { + public void solve4(int[] a) { + int len = a.length; + int maxv = Integer.MIN_VALUE; + int minv = Integer.MAX_VALUE; + for (int i : a) { + if (i > maxv) + maxv = i; + if (i < minv) + minv = i; + } + int max = maxv - minv; + int[][] dp = new int[len][max + 1]; + for (int i = 0; i < len; i++) + for (int j = 0; j <= max; j++) + dp[i][j] = 1; + int ans = 0; + int end = 0; + int dist = 0; + + for (int i = 1; i < len; i++) + for (int j = 0; j <= i - 1; j++) { + int temp = a[i] - a[j]; + if (temp > 0) { + dp[i][temp] = Math.max(dp[j][temp] + 1, dp[i][temp]); + if (dp[i][temp] > ans) { + ans = dp[i][temp]; + end = i; + dist = temp; + } + } + } + + System.out.println("result: " + ans); + int start = a[end] - (ans - 1) * dist; + for (int i = 0; i < ans; i++) + System.out.print(start + i * dist + " "); + System.out.println(); + } +} +``` + + From 6eadbc769c4f2d691519f90e5f6c2aa4444d65a5 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 22:16:09 +0800 Subject: [PATCH 053/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 86324ca..bc90366 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -360,6 +360,7 @@ public class Solution { ``` Ex8:求随机数构成的数组中最长的等差数列, 输出等差数列由小到大 + 这道题的dp[i][j]就更有点神奇了,dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢?j是等差之差,i是最后一个元素。如果能有a[i]-a[t]=j的话,那么dp[t][j]就应该能达到dp[i][j],并且dp[i][j]有可能等于dp[t][j]+1,因为和之前题目中的原因一样,有可能这个状态在之前已经被遍历过了,有更大的值,所以dp[i][j]=max(dp[t][j]+1,dp[i][j])。又,如果dp[i][j]大于我们记录的等差数列长度的最大值,则更新等差数列长度最大值,同时记录等差数列最后一个元素,等差之差。有了这三个元素就可以推出整个等差数列的元素。 ```java From 7f9fb54b3730e56bdfb3d9f097e5efc274f51652 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 21 Feb 2014 22:44:11 +0800 Subject: [PATCH 054/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index bc90366..0d48929 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -65,7 +65,7 @@ public class Solution { } } ``` -dp的作用其二,记录状态。一般记录int状态或boolean状态,下一个状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 +dp的作用其二,记录状态。一般记录int状态或boolean状态,当前状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) From 77d51d35d9e3649301dda95567020c261c3fb2cb Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 22:45:00 +0800 Subject: [PATCH 055/327] add chapter 3 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d7bbb72..ebddde7 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ 1.Permutations and Combinations$keywords Permutation, Combination -2.String dp and array dp$keywords: dp +2.String dp and array dp$keywords dp +3.Sum$keywords Sum, Tree Sum Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From ae03f52363401064137dfd650bd55bcfb7799c10 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 22:46:08 +0800 Subject: [PATCH 056/327] Create 3.Sum$keywords Sum, Tree Sum --- 3.Sum$keywords Sum, Tree Sum | 1 + 1 file changed, 1 insertion(+) create mode 100644 3.Sum$keywords Sum, Tree Sum diff --git a/3.Sum$keywords Sum, Tree Sum b/3.Sum$keywords Sum, Tree Sum new file mode 100644 index 0000000..d206229 --- /dev/null +++ b/3.Sum$keywords Sum, Tree Sum @@ -0,0 +1 @@ +##3.Sum$keywords Sum, Tree Sum From 7a67cc8b173d3b7817750ad68de7d27686708dfb Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 21 Feb 2014 22:47:33 +0800 Subject: [PATCH 057/327] Rename 3.Sum$keywords Sum, Tree Sum to 3.Sum$keywords Sum, Tree Sum.md --- 3.Sum$keywords Sum, Tree Sum => 3.Sum$keywords Sum, Tree Sum.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 3.Sum$keywords Sum, Tree Sum => 3.Sum$keywords Sum, Tree Sum.md (100%) diff --git a/3.Sum$keywords Sum, Tree Sum b/3.Sum$keywords Sum, Tree Sum.md similarity index 100% rename from 3.Sum$keywords Sum, Tree Sum rename to 3.Sum$keywords Sum, Tree Sum.md From 3b635f774d761184ccaf37ba45d0d26ba26151fd Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 22 Feb 2014 14:27:26 +0800 Subject: [PATCH 058/327] Create 3.Search Array$keywords:search.md --- 3.Search Array$keywords:search.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 3.Search Array$keywords:search.md diff --git a/3.Search Array$keywords:search.md b/3.Search Array$keywords:search.md new file mode 100644 index 0000000..0b3fd62 --- /dev/null +++ b/3.Search Array$keywords:search.md @@ -0,0 +1 @@ +#3.Search Array$keywords:search From 6adae9b7c4e1fcd116b64bb8d677795a3f6ca295 Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 22 Feb 2014 14:28:15 +0800 Subject: [PATCH 059/327] Update and rename 3.Sum$keywords Sum, Tree Sum.md to 4.Sum$keywords Sum, Tree Sum.md --- 3.Sum$keywords Sum, Tree Sum.md | 1 - 4.Sum$keywords Sum, Tree Sum.md | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 3.Sum$keywords Sum, Tree Sum.md create mode 100644 4.Sum$keywords Sum, Tree Sum.md diff --git a/3.Sum$keywords Sum, Tree Sum.md b/3.Sum$keywords Sum, Tree Sum.md deleted file mode 100644 index d206229..0000000 --- a/3.Sum$keywords Sum, Tree Sum.md +++ /dev/null @@ -1 +0,0 @@ -##3.Sum$keywords Sum, Tree Sum diff --git a/4.Sum$keywords Sum, Tree Sum.md b/4.Sum$keywords Sum, Tree Sum.md new file mode 100644 index 0000000..481a480 --- /dev/null +++ b/4.Sum$keywords Sum, Tree Sum.md @@ -0,0 +1 @@ +##4.Sum$keywords Sum, Tree Sum From 14be360b2545e7e4a250f0ecb5e6ff22d2593dde Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 22 Feb 2014 14:29:25 +0800 Subject: [PATCH 060/327] Update and rename 4.Sum$keywords Sum, Tree Sum.md to 3.Sum$keywords Sum, Tree Sum.md --- 3.Sum$keywords Sum, Tree Sum.md | 1 + 4.Sum$keywords Sum, Tree Sum.md | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 3.Sum$keywords Sum, Tree Sum.md delete mode 100644 4.Sum$keywords Sum, Tree Sum.md diff --git a/3.Sum$keywords Sum, Tree Sum.md b/3.Sum$keywords Sum, Tree Sum.md new file mode 100644 index 0000000..d206229 --- /dev/null +++ b/3.Sum$keywords Sum, Tree Sum.md @@ -0,0 +1 @@ +##3.Sum$keywords Sum, Tree Sum diff --git a/4.Sum$keywords Sum, Tree Sum.md b/4.Sum$keywords Sum, Tree Sum.md deleted file mode 100644 index 481a480..0000000 --- a/4.Sum$keywords Sum, Tree Sum.md +++ /dev/null @@ -1 +0,0 @@ -##4.Sum$keywords Sum, Tree Sum From 9957154eca53fd10f0bc19028318eb89e427513c Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 22 Feb 2014 14:57:41 +0800 Subject: [PATCH 061/327] Update Ex1 --- 3.Search Array$keywords:search.md | 1 - 4.Search Array$keywords:search.md | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) delete mode 100644 3.Search Array$keywords:search.md create mode 100644 4.Search Array$keywords:search.md diff --git a/3.Search Array$keywords:search.md b/3.Search Array$keywords:search.md deleted file mode 100644 index 0b3fd62..0000000 --- a/3.Search Array$keywords:search.md +++ /dev/null @@ -1 +0,0 @@ -#3.Search Array$keywords:search diff --git a/4.Search Array$keywords:search.md b/4.Search Array$keywords:search.md new file mode 100644 index 0000000..22a4829 --- /dev/null +++ b/4.Search Array$keywords:search.md @@ -0,0 +1,23 @@ +#4.Search Array$keywords:search +##Search array + +Ex1:[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/) + +两个变量,ones和twos,顺序遍历并且求出异或值,ones表示异或值哪些位 比特1出现一次,twos表示异或值哪些位 比特1出现两次,当异或值的某些位 比特1出现三次的时候,就要对其进行清除,这样就能保证最后得到的ones就是出现一次的数 +```java +public class Solution { + public int singleNumber(int[] A) { + int one = 0, two = 0, erase = 0; + for (int i = 0; i < A.length; i++) { + two ^= one & A[i]; + one ^= A[i]; + erase = ~(one & two); + two &= erase; + one &= erase; + } + + return one; + } +} +``` + From 35136a7f836e06147604f4fe5302e58d628d5d9b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 22 Feb 2014 15:10:40 +0800 Subject: [PATCH 062/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebddde7..454ad37 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ 1.Permutations and Combinations$keywords Permutation, Combination -2.String dp and array dp$keywords dp +2.String dp and array dp$keywords dp 3.Sum$keywords Sum, Tree Sum Core contributors ------------ From ed45d1c655658e1ae1cbbe90c07bc3ee1a72282e Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 22 Feb 2014 17:03:43 +0800 Subject: [PATCH 063/327] Update 4.Search Array$keywords:search.md --- 4.Search Array$keywords:search.md | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/4.Search Array$keywords:search.md b/4.Search Array$keywords:search.md index 22a4829..1fc84b5 100644 --- a/4.Search Array$keywords:search.md +++ b/4.Search Array$keywords:search.md @@ -21,3 +21,49 @@ public class Solution { } ``` +Ex2:[Leetcode:Best Time to Buy and Sell Stock III](http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/) + +分别记录到i时,0-i的最大利润和i+1到len-1的最大利润,相加即可。 +```java +public class Solution { + public int maxProfit(int[] prices) { + if (prices == null || prices.length < 2) return 0; + int[] forwardMax = new int[prices.length]; + int[] backwardMax = new int[prices.length]; + + int buyPoint = prices[0]; + int sellPoint = prices[0]; + int maxProfit = 0; + forwardMax[0] = 0; + + for (int i = 1; i < prices.length; i++) { + if (prices[i] < buyPoint) { + buyPoint = prices[i]; + } + forwardMax[i] = Math.max(prices[i] - buyPoint, forwardMax[i - 1]); + } + sellPoint = prices[prices.length - 1]; + backwardMax[prices.length - 1] = 0; + + for (int i = prices.length - 2; i >= 0; i--) { + if (prices[i] > sellPoint) { + sellPoint = prices[i]; + } + backwardMax[i] = Math.max(sellPoint - prices[i], backwardMax[i + 1]); + } + + int max = 0; + for (int i = 0; i < prices.length - 1; i++) { + if (forwardMax[i] + backwardMax[i + 1] > max) { + max = forwardMax[i] + backwardMax[i + 1]; + } + } + if (max < Math.max(forwardMax[prices.length - 1], backwardMax[0])) { + max = Math.max(forwardMax[prices.length - 1], backwardMax[0]); + } + return max; + } +} +``` + +Ex3: From 222d501754924bc05e243907b666b5be8e6f9ab2 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 22 Feb 2014 19:43:05 +0800 Subject: [PATCH 064/327] add chapter 4 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 454ad37..25b2c51 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ Chapters ------------ 1.Permutations and Combinations$keywords Permutation, Combination 2.String dp and array dp$keywords dp -3.Sum$keywords Sum, Tree Sum +3.Sum$keywords Sum, Tree Sum +4.Search Array$keywords search Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 077bf2d9114a401f4825a5829a34da50cdf17d1d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 22 Feb 2014 19:45:58 +0800 Subject: [PATCH 065/327] delete invalid symbol ":" in title --- ... Array$keywords:search.md => 4.Search Array$keywords search.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 4.Search Array$keywords:search.md => 4.Search Array$keywords search.md (100%) diff --git a/4.Search Array$keywords:search.md b/4.Search Array$keywords search.md similarity index 100% rename from 4.Search Array$keywords:search.md rename to 4.Search Array$keywords search.md From c28640039b75c54463fc250ca6f43d3691711cc6 Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 23 Feb 2014 18:44:34 +0800 Subject: [PATCH 066/327] Update 4.Search Array$keywords search.md Ex4 update --- 4.Search Array$keywords search.md | 119 +++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 1fc84b5..0e4a39b 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -66,4 +66,121 @@ public class Solution { } ``` -Ex3: +Ex3:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 + +使用普通的比较时间复杂度是n方。这里介绍一种复杂度为nlogn的方法。该方法要借助二分排序,即将数组分为两部分分别排序。之后在对两个子数组进行merge的时候,去比较子数组1的当前元素和子数组2的当前元素,若1大于2,则说明1后面的元素都大于2,所以都为逆序对,将这些数加入结果集。 +```java +public class Main { + static long count = 0; + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + while (in.hasNext()) { + int n = in.nextInt(); + int[] a = new int[n]; + for (int i = 0; i < n; i++) + a[i] = in.nextInt(); + count = 0; + mergeSort(a); + System.out.println(count); + } + } + + // 将有二个有序数列a[first...mid]和a[mid...last]合并。 + static void mergearray(int a[], int first, int mid, int last, int temp[]) { + int i = first, j = mid + 1; + int m = mid, n = last; + int k = 0; + while (i <= m && j <= n) { + if (a[i] > a[j]) { + // 左数组比右数组大 + temp[k++] = a[j++]; + // 因为如果a[i]此时比右数组的当前元素a[j]大, + // 那么左数组中a[i]后面的元素就都比a[j]大 + // 【因为数组此时是有序数组】 + count += mid - i + 1; + } else { + temp[k++] = a[i++]; + } + } + while (i <= m) { + temp[k++] = a[i++]; + } + while (j <= n) { + temp[k++] = a[j++]; + } + for (i = 0; i < k; i++) + a[first + i] = temp[i]; + } + + static void mergesort(int a[], int first, int last, int temp[]) { + if (first < last) { + int mid = (first + last) / 2; + mergesort(a, first, mid, temp); // 左边有序 + mergesort(a, mid + 1, last, temp); // 右边有序 + mergearray(a, first, mid, last, temp); // 再将二个有序数列合并 + } + } + + static void mergeSort(int a[]) { + int[] p = new int[a.length]; + mergesort(a, 0, a.length - 1, p); + } +} +``` + +Ex4:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 + +在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组 + +```cpp +#include +#include +#include +#include +using namespace std; +#define LL long long +void swap(LL *a, LL *b){ + LL tmp=*a; + *a=*b; + *b=tmp; +} + +int partition_arr(int low,int high,LL *arr,const int k){ + if(low>=high) + return 0; + LL tmp=arr[low]; + int i=low,j=high+1; + LL pivot=arr[low]; + while(1){ + while(arr[++i]pivot); + if(i=k){ + printf("%d",arr[0]); + for(i=1;i Date: Sun, 23 Feb 2014 18:45:31 +0800 Subject: [PATCH 067/327] Update 4.Search Array$keywords search.md --- 4.Search Array$keywords search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 0e4a39b..1c39e27 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -1,5 +1,5 @@ #4.Search Array$keywords:search -##Search array +##*Search array Ex1:[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/) From 66618ccf6235d4a9ebe1f1485fde28ff7462cca7 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 19:03:14 +0800 Subject: [PATCH 068/327] add isPalindrome dp solution to Ex1 --- 2.String dp and Array dp$keywords dp.md | 28 ++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 0d48929..fbcd3c6 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -4,8 +4,9 @@ dp有几种用途,其中之一就是标记和剪枝 Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/) -该题dp的作用就是标记和剪枝,使用二维dp[i][len]来表示i i+len-1之间是否有继续搜索的必要,即是否可以将i i+len-1之间的串切成回文。 -标记是在搜索之前判断的,之后就可dfs来搜索 +该题dp的作用就是标记和剪枝,使用二维dp[i][len]来表示i i+len-1之间是否有继续搜索的必要,即是否可以将i i+len-1之间的串切成回文。标记是在搜索之前判断的,之后就可dfs来搜索。 + +Note by [@sc703bupt](https://github.com/sc703bupt): isPalindrome方法也可以应用dp以避免重复计算,提高速度。具体做法是使用一个二维数组记录s的所有子串的是否是回文串,如dp[i][j]表示s从i到j的子串是否是回文串,求解时以每个字符为中心向两侧探测。 ```java public class Solution { ArrayList> all = new ArrayList>(); @@ -64,7 +65,28 @@ public class Solution { return true; } } -``` +``` +```java + boolean[][] isPalindrome = new boolean[s.length()+1][s.length()+1]; + void isPalindrome(String s){ + for (int i=0; i Date: Sun, 23 Feb 2014 19:06:02 +0800 Subject: [PATCH 069/327] update isPalindrome dp solution to Ex1 --- 2.String dp and Array dp$keywords dp.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index fbcd3c6..6689385 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -6,7 +6,7 @@ Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindr 该题dp的作用就是标记和剪枝,使用二维dp[i][len]来表示i i+len-1之间是否有继续搜索的必要,即是否可以将i i+len-1之间的串切成回文。标记是在搜索之前判断的,之后就可dfs来搜索。 -Note by [@sc703bupt](https://github.com/sc703bupt): isPalindrome方法也可以应用dp以避免重复计算,提高速度。具体做法是使用一个二维数组记录s的所有子串的是否是回文串,如dp[i][j]表示s从i到j的子串是否是回文串,求解时以每个字符为中心向两侧探测。 +Note by [@sc703bupt](https://github.com/sc703bupt): isPalindrome方法也可以应用dp以避免重复计算,提高速度。具体做法是使用一个二维数组记录s的所有子串的是否是回文串,如dp[i][j]表示s从i到j的子串是否是回文串,求解时以每个字符为中心向两侧探测,注意奇偶情况分别求解。 ```java public class Solution { ArrayList> all = new ArrayList>(); @@ -66,6 +66,7 @@ public class Solution { } } ``` +isPalindrome的dp解法: ```java boolean[][] isPalindrome = new boolean[s.length()+1][s.length()+1]; void isPalindrome(String s){ From d29468ff4d4128a4dd32f1f939820e86142da69d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 19:24:08 +0800 Subject: [PATCH 070/327] add another dp solution to Ex4 --- 2.String dp and Array dp$keywords dp.md | 38 +++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 6689385..144f633 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -178,7 +178,9 @@ public: Ex4:[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/) -两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 +两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 + +Add by[@sc703bupt](https://github.com/sc703bupt): 给出一种“正向”迭代式dp解法,c++代码。 ```java public class Solution { public int minDistance(String word1, String word2) { @@ -215,8 +217,38 @@ public class Solution { return result; } } -``` - +``` +迭代式dp解法: +```cpp +class Solution { +public: + int minDistance(string word1, string word2) { + vector > record; + record.resize(word1.size()+1); + for(int i = 0; i <= word1.size(); i++){ + for(int j = 0; j <= word2.size(); j++){ + record[i].push_back(0); + } + //record.push_back(vector(word2.size()+1)); + record[i][0] = i; + } + for(int j = 0; j <= word2.size(); j++){ + record[0][j] = j; + } + int tempMin = 0, subVal = 0; + for(int i = 1; i <= word1.size(); i++){ + for(int j = 1; j <= word2.size(); j++){ + tempMin = record[i][j-1] + 1;//add + tempMin = tempMin < record[i-1][j] + 1?tempMin:record[i-1][j] + 1;//delete + subVal = ((word1[i-1] == word2[j-1])?0:1);//judge current char word1[i] and word2[j] + tempMin = tempMin < record[i-1][j-1] + subVal?tempMin:record[i-1][j-1] + subVal;//revise + record[i][j] = tempMin; + } + } + return record[word1.size()][word2.size()]; + } +}; +``` ###*Array dp Ex5:最长公共子序列(LCS):请编写一个函数,输入两个字符串,求它们的最长公共子序列长度,并打印出最长公共子序列。 From 6bc02ad6e9401f5929fd7cc03194fc7f9256490b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 20:23:51 +0800 Subject: [PATCH 071/327] revise "route" to "mark" in Ex5 description --- 2.String dp and Array dp$keywords dp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 144f633..fd2bb0b 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -253,7 +253,7 @@ public: Ex5:最长公共子序列(LCS):请编写一个函数,输入两个字符串,求它们的最长公共子序列长度,并打印出最长公共子序列。 -经典的动态规划问题。dp[i][j]表示p1的前i的个字符和p2的前j个字符匹配的最大长度。定位到dp[i][j]。若p1中的第i个字符与p2的第j个字符相等,则dp[i][j]=dp[i-1][j-1]+1;若不相等,则为dp[i-1][j]和dp[i][j-1]中较大的一个。关键问题是如何打印最长公共子序列。这里我们可以再使用一个二维数组route来标记当前的状态是从哪一个状态得来。route[i][j]有三个值,分别为1 2 3,1表示由dp[i-1][j]得来,2表示由dp[i-1][j-1]得来,3表示由dp[i][j-1]得来。当得到最长公共子序列的长度后,dp[p1.length()-1][p2.length()-1]开始向前查找,route[i][j]为1 i--,为3 j--,为2 i-- j--并将当前值填入结果数组。最后将数组逆序输出即可。 +经典的动态规划问题。dp[i][j]表示p1的前i的个字符和p2的前j个字符匹配的最大长度。定位到dp[i][j]。若p1中的第i个字符与p2的第j个字符相等,则dp[i][j]=dp[i-1][j-1]+1;若不相等,则为dp[i-1][j]和dp[i][j-1]中较大的一个。关键问题是如何打印最长公共子序列。这里我们可以再使用一个二维数组mark来标记当前的状态是从哪一个状态得来。mark[i][j]有三个值,分别为1 2 3,1表示由dp[i-1][j]得来,2表示由dp[i-1][j-1]得来,3表示由dp[i][j-1]得来。当得到最长公共子序列的长度后,dp[p1.length()-1][p2.length()-1]开始向前查找,mark[i][j]为1 i--,为3 j--,为2 i-- j--并将当前值填入结果数组。最后将数组逆序输出即可。 ```java import java.util.ArrayList; From f368a5675e2b249f31212a438de4672b2cb37ea3 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 21:58:18 +0800 Subject: [PATCH 072/327] finish Ex3 and revise title --- 3.Sum$keywords Sum, Tree Sum.md | 1 - 3.Sum$keywords Vector Sum, Tree Sum.md | 169 +++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) delete mode 100644 3.Sum$keywords Sum, Tree Sum.md create mode 100644 3.Sum$keywords Vector Sum, Tree Sum.md diff --git a/3.Sum$keywords Sum, Tree Sum.md b/3.Sum$keywords Sum, Tree Sum.md deleted file mode 100644 index d206229..0000000 --- a/3.Sum$keywords Sum, Tree Sum.md +++ /dev/null @@ -1 +0,0 @@ -##3.Sum$keywords Sum, Tree Sum diff --git a/3.Sum$keywords Vector Sum, Tree Sum.md b/3.Sum$keywords Vector Sum, Tree Sum.md new file mode 100644 index 0000000..e90d8cb --- /dev/null +++ b/3.Sum$keywords Vector Sum, Tree Sum.md @@ -0,0 +1,169 @@ +##3.Sum$keywords Vector Sum, Tree Sum +###*Sum + +Sum问题指的是从给定的数列中寻找和为定值的k个数(k可以为2,3,4以及任意不等)以及由此衍生的问题。对于有序序列的Sum(k=2)问题,可以使用两指针贪心算法;对于无序序列,可以排序再应用上述方法,也可以使用map方法。 + +Ex1:[LeetCode:Two Sum](http://oj.leetcode.com/problems/two-sum/) + +本系列中的基础题,寻找两个数和为给定值。这里展示map方法,即把数列以的形式存入map,然后使用target-numbers[i]查找。注意输出格式。 +```cpp +class Solution { +public: + vector twoSum(vector &numbers, int target) { + map temp; + vector result; + + for(int i = 0;i<=numbers.size()-1;i++){ + temp.insert(pair(numbers.at(i),i+1)); + } + for(int i = 0;i<=numbers.size()-1;i++){ + map::iterator itr = temp.find(target-numbers.at(i)); + if(itr!=temp.end()){ + if(itr->second == i+1){ + continue; + } + if(itr->secondsecond); + result.push_back(i+1); + }else{ + result.push_back(i+1); + result.push_back(itr->second); + } + return result; + } + } + return result; + } +}; +``` + +Ex2:[LeetCode:3Sum](http://oj.leetcode.com/problems/3sum/) + +寻找和为定值的3个数可以通过事先选定一个数降维为two sum问题,同理寻找和为定值的k个数都可以通过多次降维最终通过two sum解决,此题虽然求得是3sum,这里给出ksum的通用解法。其中k==2的递归出口使用的就是两指针贪心法。 + +**注意**,为了使用两指针方法,必须对数列**预先排序**。 +```cpp +class Solution { +public: + vector > threeSum(vector &num) { + vector> ret; + if(num.size()<3) return ret; + sort(num.begin(), num.end()); + ret = findKSum(num, 0, 3, 0); + return ret; + } + + vector > findKSum(vector &num, int start, int k, int target){//require sorted vector + vector> ret; + unordered_set visited; + if(k == 2){ + int i = start, j = num.size()-1; + while(i < j){ + if(visited.find(num[i]) != visited.end()){ + i++; + continue; + } + + int sum = num[i] + num[j]; + if(sum == target){ + vector tempV; + tempV.push_back(num[i]); + tempV.push_back(num[j]); + visited.insert(num[i]); + visited.insert(num[j]); + ret.push_back(tempV); + i++; + j--; + }else if(sum < target){ + i++; + }else{ + j--; + } + } + }else{ + for(int i = start; i <= num.size()-1; i++){ + if(visited.find(num[i]) != visited.end()){ + continue; + }else{ + visited.insert(num[i]); + vector> tempRet = findKSum(num, i+1, k-1, target-num[i]); + if(!tempRet.empty()){ + for(int j = 0; j <= tempRet.size()-1; j++){ + tempRet[j].insert(tempRet[j].begin(), num[i]); + ret.push_back(tempRet[j]); + } + } + } + } + } + return ret; + } +}; +``` +Ex3:[LeetCode:4Sum](http://oj.leetcode.com/problems/4sum/) + +此题仍然可以应用3Sum中通用解法,这里展示的是4sum的map解法,获得<2sum,set>>便可以应用类似2Sum的求解方法。 + +```cpp +class Solution { +public: + vector > fourSum(vector &num, int target) { + vector> ret; + set> tempRet; + if(num.size() < 3) return ret; + sort(num.begin(), num.end()); + + unordered_map>> record; + for(int i = 0; i <= num.size()-2; i++){ + for(int j = i+1; j <= num.size()-1; j++){ + int sum = num[i] + num[j]; + unordered_map>>::iterator itr = record.find(sum); + if(itr != record.end()){ + pair p(i, j); + (itr->second).insert(p); + }else{ + set> s; + pair p(i, j); + s.insert(p); + record[sum] = s; + } + } + } + + unordered_set visited; + unordered_map>>::iterator itr1 = record.begin(); + for(;itr1 != record.end(); itr1++){ + if(visited.find(itr1->first) != visited.end()) continue; + visited.insert(itr1->first); + unordered_map>>::iterator itr2 = record.find(target-(itr1->first)); + if(itr2 != record.end()){ + visited.insert(itr2->first); + set>::iterator itr2S = (itr2->second).begin(); + for(; itr2S != (itr2->second).end(); itr2S++){ + set>::iterator itr1S = (itr1->second).begin(); + for(; itr1S != (itr1->second).end(); itr1S++){ + if(itr2S->first == itr1S->first || itr2S->first == itr1S->second || + itr2S->second == itr1S->first || itr2S->second == itr1S->second){ + continue; + }else{ + vector temp; + temp.push_back(num[itr2S->first]); + temp.push_back(num[itr2S->second]); + temp.push_back(num[itr1S->first]); + temp.push_back(num[itr1S->second]); + sort(temp.begin(), temp.end()); + tempRet.insert(temp); + } + } + } + } + } + for(set>::iterator itr = tempRet.begin(); itr != tempRet.end(); itr++){ + ret.push_back(*itr); + } + return ret; + } +}; +``` + +Ex4:[LeetCode:3sum-closest](http://oj.leetcode.com/problems/3sum-closest/) From 0914bdc4127270111690f54887d183ae69fbb5de Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 21:59:29 +0800 Subject: [PATCH 073/327] revise keyword of Chapter 3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 25b2c51..cc9db8c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Chapters ------------ 1.Permutations and Combinations$keywords Permutation, Combination 2.String dp and array dp$keywords dp -3.Sum$keywords Sum, Tree Sum +3.Sum$keywords Vector Sum, Tree Sum 4.Search Array$keywords search Core contributors ------------ From 4b9e593438749cebff04d1ecfe2204e2815e54e0 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 22:08:14 +0800 Subject: [PATCH 074/327] add Ex4 --- 3.Sum$keywords Vector Sum, Tree Sum.md | 53 +++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum.md b/3.Sum$keywords Vector Sum, Tree Sum.md index e90d8cb..65d9501 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum.md @@ -1,11 +1,10 @@ ##3.Sum$keywords Vector Sum, Tree Sum -###*Sum - -Sum问题指的是从给定的数列中寻找和为定值的k个数(k可以为2,3,4以及任意不等)以及由此衍生的问题。对于有序序列的Sum(k=2)问题,可以使用两指针贪心算法;对于无序序列,可以排序再应用上述方法,也可以使用map方法。 +###*Vector Sum +Vector Sum问题指的是从给定的数列中寻找和为定值的k个数(k可以为2,3,4以及任意不等)以及由此衍生的问题。对于有序序列的Sum(k=2)问题,可以使用两指针贪心算法;对于无序序列,可以排序再应用上述方法,也可以使用map方法。 Ex1:[LeetCode:Two Sum](http://oj.leetcode.com/problems/two-sum/) -本系列中的基础题,寻找两个数和为给定值。这里展示map方法,即把数列以的形式存入map,然后使用target-numbers[i]查找。注意输出格式。 +本系列中的基础题,寻找两个数和为给定值。这里展示map方法,即把数列以(value,positon)的形式存入map,然后使用target-numbers[i]查找。注意输出格式。 ```cpp class Solution { public: @@ -102,7 +101,7 @@ public: ``` Ex3:[LeetCode:4Sum](http://oj.leetcode.com/problems/4sum/) -此题仍然可以应用3Sum中通用解法,这里展示的是4sum的map解法,获得<2sum,set>>便可以应用类似2Sum的求解方法。 +此题仍然可以应用3Sum中通用解法,这里展示的是4sum的map解法,获得(2sum,set(pair(num1,num2)))的map便可以应用类似2Sum的求解方法。 ```cpp class Solution { @@ -167,3 +166,47 @@ public: ``` Ex4:[LeetCode:3sum-closest](http://oj.leetcode.com/problems/3sum-closest/) +与前述题差异在于求解的是和与目标最接近的3个数。仍然应用Ex2中的通用解法,但在k==2的逻辑上略有改动。需要注意的是多了preSum和originT作为辅助实现,结果成立约束条件注意不要把target和originT混用。 +```cpp +class Solution { +public: + int ret; + int threeSumClosest(vector &num, int target) { + sort(num.begin(), num.end()); + ret = num[0]+num[1]+num[2]; + findKSum(num, 0, 0, 3, target, target); + return ret; + } + + void findKSum(vector &num,int preSum, int start, int k, int target, int originT){//require sorted vector + unordered_set visited; + if(k == 2){ + int i = start, j = num.size()-1; + while(i < j){ + int sum = num[i] + num[j]; + if(abs(originT-sum-preSum) < abs(originT-ret)){ + ret = sum + preSum; + if(ret == originT) return; + } + if(sum == target){ + i++; + j--; + }else if(sum < target){ + i++; + }else{ + j--; + } + } + }else{ + for(int i = start; i <= num.size()-1; i++){ + if(visited.find(num[i]) != visited.end()){ + continue; + }else{ + visited.insert(num[i]); + findKSum(num, preSum+num[i], i+1, k-1, target-num[i], originT); + } + } + } + } +}; +``` From ad0fe521f633560d033c01843fc6755459f56397 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 22:10:45 +0800 Subject: [PATCH 075/327] remove Ex6 and Ex7 to Chapter 3, revise Ex8 to Ex6 --- ...tions$keywords Permutation, Combination.md | 126 +----------------- 1 file changed, 1 insertion(+), 125 deletions(-) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index b2faa15..0ddd70f 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -228,131 +228,7 @@ public: }; ``` -Ex6:[LeetCode:Combination Sum](http://oj.leetcode.com/problems/combination-sum/) - -此题要求一定条件下的组合数,思路与Ex5类似,只不过对于每个数有不选,选1,选2个...选n个共n+1个选择,注意剪枝。使用Set去重,暂时没考虑在求解过程中自动去重(对candidates排序,看当前数字和前一个数字是否相同进行去重可能可行)。 -```cpp -class Solution { -public: - set > resultSet; - vector > combinationSum(vector &candidates, int target) { - vector > result; - vector temp; - if(candidates.size() == 0) return result; - sort(candidates.begin(),candidates.end()); - compute(temp, candidates, 0, 0, target); - for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ - result.push_back(*itr); - } - return result; - } - - void compute(vector temp, vector& candidates, int index, int currentVal, int target){ - if(index == candidates.size()) return; - - compute(temp, candidates, index+1, currentVal, target); - - for(int i = 1; currentVal + i * candidates[index] <= target; i++){ - temp.push_back(candidates[index]); - if(currentVal + i * candidates[index] == target){ - resultSet.insert(temp); - }else{ - compute(temp, candidates, index+1, currentVal+i*candidates[index], target); - } - } - - return; - } -}; -``` - -Ex7:[LeetCode:Combination Sum II](http://oj.leetcode.com/problems/combination-sum-ii/) - -此题与Ex6区别在于每个数只能用一次,该问题更确切的说是一个01背包问题,使用Set去重,应用以下剪枝方法需要对待选数字升序排序。 - -01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k!=M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 - -**选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk+Σ(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 - -**不选择k**:若t+r-k>=M&&t+(k+1)<=M,一方面判断剩下的物品还足够填满M,同时同选择k情形判断第k+1个物品是否使得X的解可能存在。 - -```cpp -class Solution { -public: - - set > resultSet; - vector > combinationSum2(vector &num, int target) { - vector > result; - if(num.size() == 0) return result; - vector temp; - temp.clear(); - sort(num.begin(), num.end()); - int rest = 0; - for(int i = 0; i<=num.size()-1; i++){ - rest += num[i]; - } - compute(temp, num, 0, rest, target); - for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ - result.push_back(*itr); - } - - return result; - } - - - //优化剪枝的递归函数 92ms - void compute(vector& temp, vector num, int currentVal, int restVal, int target){ - if(num.size() == 0) return; - - if(currentVal + num[0] == target){ - temp.push_back(num[0]); - resultSet.insert(temp); - temp.pop_back(); - return; - } - - if(num.size() == 1) return; - - if(currentVal + num[0] + num[1] <= target){ - temp.push_back(num[0]); - compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); - temp.pop_back(); - } - - if(currentVal + restVal - num[0] >= target && currentVal + num[1] <= target){ - compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); - } - - return; - } - - - //未优化剪枝的递归函数 1160ms - /* - void compute(vector& temp, vector num, int currentVal, int restVal, int target){ - if(num.size() == 0) return; - - if(currentVal + num[0] == target){ - temp.push_back(num[0]); - resultSet.insert(temp); - temp.pop_back(); - return; - } - - if(currentVal + num[0] <= target){ - temp.push_back(num[0]); - compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); - temp.pop_back(); - } - - compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); - - return; - }*/ -}; -``` - -Ex8:[LeetCode:Letter Combinations of a Phone Number ](http://oj.leetcode.com/problems/letter-combinations-of-a-phone-number/) +Ex6:[LeetCode:Letter Combinations of a Phone Number ](http://oj.leetcode.com/problems/letter-combinations-of-a-phone-number/) 递归方法,做好映射,对每个数字的可能情况进行递归。 From 1305d4b2e760c0ffb2f0208546b200849da2727d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 22:14:32 +0800 Subject: [PATCH 076/327] add Ex6 --- 3.Sum$keywords Vector Sum, Tree Sum.md | 123 +++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/3.Sum$keywords Vector Sum, Tree Sum.md b/3.Sum$keywords Vector Sum, Tree Sum.md index 65d9501..22636a0 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum.md @@ -210,3 +210,126 @@ public: } }; ``` +Ex5:[LeetCode:Combination Sum](http://oj.leetcode.com/problems/combination-sum/) + +此题要求给定目标和的组合数,对于每个数有不选,选1,选2个...选n个共n+1个选择,注意剪枝。使用Set去重,暂时没考虑在求解过程中自动去重(对candidates排序,看当前数字和前一个数字是否相同进行去重可能可行)。 +```cpp +class Solution { +public: + set > resultSet; + vector > combinationSum(vector &candidates, int target) { + vector > result; + vector temp; + if(candidates.size() == 0) return result; + sort(candidates.begin(),candidates.end()); + compute(temp, candidates, 0, 0, target); + for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ + result.push_back(*itr); + } + return result; + } + + void compute(vector temp, vector& candidates, int index, int currentVal, int target){ + if(index == candidates.size()) return; + + compute(temp, candidates, index+1, currentVal, target); + + for(int i = 1; currentVal + i * candidates[index] <= target; i++){ + temp.push_back(candidates[index]); + if(currentVal + i * candidates[index] == target){ + resultSet.insert(temp); + }else{ + compute(temp, candidates, index+1, currentVal+i*candidates[index], target); + } + } + + return; + } +}; +``` + +Ex6:[LeetCode:Combination Sum II](http://oj.leetcode.com/problems/combination-sum-ii/) + +此题与Ex5区别在于每个数只能用一次,该问题更确切的说是一个01背包问题,使用Set去重,应用以下剪枝方法需要对待选数字升序排序。 + +01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k!=M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 + +**选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk+Σ(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 + +**不选择k**:若t+r-k>=M&&t+(k+1)<=M,一方面判断剩下的物品还足够填满M,同时同选择k情形判断第k+1个物品是否使得X的解可能存在。 + +```cpp +class Solution { +public: + + set > resultSet; + vector > combinationSum2(vector &num, int target) { + vector > result; + if(num.size() == 0) return result; + vector temp; + temp.clear(); + sort(num.begin(), num.end()); + int rest = 0; + for(int i = 0; i<=num.size()-1; i++){ + rest += num[i]; + } + compute(temp, num, 0, rest, target); + for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ + result.push_back(*itr); + } + + return result; + } + + + //优化剪枝的递归函数 92ms + void compute(vector& temp, vector num, int currentVal, int restVal, int target){ + if(num.size() == 0) return; + + if(currentVal + num[0] == target){ + temp.push_back(num[0]); + resultSet.insert(temp); + temp.pop_back(); + return; + } + + if(num.size() == 1) return; + + if(currentVal + num[0] + num[1] <= target){ + temp.push_back(num[0]); + compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); + temp.pop_back(); + } + + if(currentVal + restVal - num[0] >= target && currentVal + num[1] <= target){ + compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); + } + + return; + } + + + //未优化剪枝的递归函数 1160ms + /* + void compute(vector& temp, vector num, int currentVal, int restVal, int target){ + if(num.size() == 0) return; + + if(currentVal + num[0] == target){ + temp.push_back(num[0]); + resultSet.insert(temp); + temp.pop_back(); + return; + } + + if(currentVal + num[0] <= target){ + temp.push_back(num[0]); + compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); + temp.pop_back(); + } + + compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); + + return; + }*/ +}; +``` From 247382f47032ae53a70307aead39f0890127fac3 Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 23 Feb 2014 22:16:08 +0800 Subject: [PATCH 077/327] Update 4.Search Array$keywords search.md Ex5 uodated --- 4.Search Array$keywords search.md | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 1c39e27..fc14577 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -184,3 +184,67 @@ int main() return 0; } ``` + +Ex5:任意给定一个正整数N,求一个最小的M(M>1),使得N*M的十进制表示形式里只含有1和0。 + +首先我们要维护一个余数信息数组,里面存放的是满足表示形式为1和0的,求余N为j的最小的数。若10的i次幂求余N等于j的话,就将这个数加入余数数组。然后遍历已经存在的余数信息数组。假设10的p次幂求余N等于k,则(10的p次幂+10的i次幂)% N =(j+k)%N,所以将余数为k的数和余数为j的数加入余数为(j+k)的数组中。下面是解决这道题的算法,想要看懂该算法需要明白两个条件:(1)(x*10)% N = (x%N*10)% N (2)在一轮N次更新后,如果余数数组没有出现更新,那么将进入死循环,不再有结果,退出 +```java +import java.util.ArrayList; + +public class MyOwn { + public void Only10(int N) { + ArrayList> b = new ArrayList>(); + for (int i = 0; i < N; i++) + b.add(new ArrayList()); + b.get(1).add(0); + int noUpdate = 0; + + for (int i = 1, j = 10 % N;; i++, j = (j * 10) % N) { + boolean flag = false; + if (b.get(j).size() == 0) { + flag = true; + b.get(j).add(i); + } + for (int k = 1; k < N; k++) { + if (b.get(k).size() > 0 + && i > b.get(k).get(b.get(k).size() - 1) + && b.get((j + k) % N).size() == 0) { + flag = true; + b.set((j + k) % N, b.get(k)); + b.get((j + k) % N).add(i); + } + } + + if (flag) + noUpdate = 0; + else + noUpdate++; + + if (noUpdate == N || b.get(0).size() > 0) + break; + } + + if (noUpdate == N) + System.out.println("Not Exit"); + else { + int max = b.get(0).get(b.get(0).size() - 1); + long result = 0; + for (int i = max; i >= 0; i--) { + if (b.get(0).contains(i)) + result = result * 10 + 1; + else + result = result * 10; + } + // if (b.get(0).get(0) == 0) + // result = result * 10; + System.out.println("result: " + result); + System.out.println("N: " + N + " M: " + result / N); + } + } + + public static void main(String[] args) { + MyOwn m = new MyOwn(); + m.Only10(24); + } +} +``` From 4cc92494d65032b7f13bb6b598565d5e96698dbb Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 23 Feb 2014 22:27:09 +0800 Subject: [PATCH 078/327] Update 4.Search Array$keywords search.md Ex6 updated --- 4.Search Array$keywords search.md | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index fc14577..6e095de 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -248,3 +248,40 @@ public class MyOwn { } } ``` + +Ex6:加强版水王,找出出现次数刚好是一半的数字:有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。 + +首先,水王占总数的一半,说明总数必为偶数;其次,最后一个元素或者是水王,或者不是水王,因此只要在扫描数组的时候每一个元素都与最后一个元素做比较,如果相等则最后一个元素的个数加1,否则不处理。如果最后一个元素的个数为N/2,(N为数组元素个数)则它就是水王,否则水王就是前面N-1个元素中选出的candidate。 +```cpp +int MoreThanHalf(int a[], int N) +{ + int sum1 = 0;//最后一个元素的个数 + int sum2 = 0; + int candidate; + int i; + for(i=0;i Date: Sun, 23 Feb 2014 22:37:19 +0800 Subject: [PATCH 079/327] Update 4.Search Array$keywords search.md Ex7 updated --- 4.Search Array$keywords search.md | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 6e095de..155c6d5 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -284,4 +284,53 @@ int MoreThanHalf(int a[], int N) } ``` +Ex7:堆排序:就是写出一个堆排序算法,对数组排序 +之所以把堆排序算在搜索里面,是因为很多时候在大数据中查找的时候,会用到堆排序。堆排序的思想就是首先建立一个大根堆,然后将堆顶和数组的最后一个元素交换,之后维护大根堆,然后再交换,如此循环。 +```java +public class MyOwn { + public void heapSort(int[] a) { + buildHeap(a); + for (int i = a.length - 1; i > 0; i--) { + swap(0, i, a); + adjust(1, i, a); + } + } + public void swap(int i, int j, int[] a) { + int tmp = a[i]; + a[i] = a[j]; + a[j] = tmp; + } + + public void adjust(int i, int max, int[] a) { + int left = 2 * i; + int right = 2 * i + 1; + int big = i; + if (max >= left && a[left - 1] > a[i - 1]) + big = left; + + if (max >= right && a[right - 1] > a[i - 1]) + big = right; + + if (big != i) { + swap(i - 1, big - 1, a); + adjust(big, max, a); + } + } + + public void buildHeap(int[] a) { + int begin = a.length / 2; + // int begin = (int) (Math.floor(a.length / 2)); + for (int i = begin; i >= 1; i--) + adjust(i, a.length, a); + } + + public static void main(String[] args) { + Solution m = new Solution(); + int[] a = { 32, 1, 9, 5, 7, 12, 0, 4 }; + m.heapSort(a); + for (int i : a) + System.out.print(i + " "); + } +} +``` From 86700e03a116c456dd38bedeb5a20b440f6b958a Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 23 Feb 2014 22:38:31 +0800 Subject: [PATCH 080/327] Update 4.Search Array$keywords search.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改ex7 --- 4.Search Array$keywords search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 155c6d5..fe4b25f 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -284,7 +284,7 @@ int MoreThanHalf(int a[], int N) } ``` -Ex7:堆排序:就是写出一个堆排序算法,对数组排序 +Ex7:堆排序:写出一个堆排序算法,对数组排序 之所以把堆排序算在搜索里面,是因为很多时候在大数据中查找的时候,会用到堆排序。堆排序的思想就是首先建立一个大根堆,然后将堆顶和数组的最后一个元素交换,之后维护大根堆,然后再交换,如此循环。 ```java public class MyOwn { From 668a15981a565bf0b31cb26cbca283e1c6c72510 Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 23 Feb 2014 22:44:06 +0800 Subject: [PATCH 081/327] Update 4.Search Array$keywords search.md update ex4 --- 4.Search Array$keywords search.md | 1 + 1 file changed, 1 insertion(+) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index fe4b25f..d2320ae 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -132,6 +132,7 @@ public class Main { Ex4:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组 +另:该题也可以用Ex7堆排序实现 ```cpp #include From ea866ba8f659102e66aa5bd6d1160f2cd765dfce Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 23 Feb 2014 22:55:46 +0800 Subject: [PATCH 082/327] add Ex7 --- 3.Sum$keywords Vector Sum, Tree Sum.md | 58 ++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/3.Sum$keywords Vector Sum, Tree Sum.md b/3.Sum$keywords Vector Sum, Tree Sum.md index 22636a0..9c38064 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum.md @@ -333,3 +333,61 @@ public: }*/ }; ``` +###*Tree Sum + +Tree Sum指在树节点中进行的有条件求和问题,对于树的遍历,最常用的方法莫过于DFS和BFS,以下例题展示这些方法是如何应用的。 + +Ex7:[LeetCode:Binary Tree Maximum Path Sum](http://oj.leetcode.com/problems/binary-tree-maximum-path-sum/) + +本题的解答写的比较繁琐,以后更新简洁解法。核心思想是递归函数返回的是当前节点的最大路径和P,注意这里所指的最大路径为当前节点到其叶子节点的单向子路径。同时使用一个全局变量或传引用变量记录路径最大值max,当前节点其能形成的最大子路径有四种情况: +* 左孩子和右孩子都不存在,最大值为Vroot +* 左孩子不存在,最大值为Vroot(如果P < 0)或Vroot+P +* 右孩子不存在,最大值为Vroot(如果P < 0)或Vroot+P < 0 +* 左孩子和右孩子都存在,最大值为Vroot、Vroot+P、Vroot+P、Vroot+P+P情形之一 + +```cpp +class Solution { +public: + int maxSum = 0x80000000; + int maxPathSum(TreeNode *root) { + if(root == NULL) return 0; + int val = recursion(root); + return val>maxSum?val:maxSum; + } + + int recursion(TreeNode* root){ + if(root == NULL) return 0; + int leftVal = 0, rightVal = 0, temp = 0; + if(root->left == NULL && root->right == NULL){ + if(root->val > maxSum) maxSum = root->val; + return root->val; + } + if(root->left == NULL){ + rightVal = recursion(root->right); + temp = rightVal < 0?root->val:root->val+rightVal; + if(temp > maxSum) maxSum = temp; + return temp; + } + if(root->right == NULL){ + leftVal = recursion(root->left); + temp = leftVal < 0?root->val:root->val+leftVal; + if(temp > maxSum) maxSum = temp; + return temp; + } + + rightVal = recursion(root->right); + leftVal = recursion(root->left); + if(root->val > maxSum) maxSum = root->val; + if(root->val+rightVal > maxSum) maxSum = root->val+rightVal; + if(root->val+leftVal > maxSum) maxSum = root->val+leftVal; + if(leftVal + rightVal + root->val > maxSum){ + maxSum = leftVal + rightVal + root->val; + } + if(leftVal < 0 && rightVal < 0){ + return root->val; + }else{ + return leftVal>rightVal?leftVal+root->val:rightVal+root->val; + } + } +}; +``` From 39c6f2c5307f5eccdafd84da401769549ca542a8 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 09:15:03 +0800 Subject: [PATCH 083/327] add Ex10, add keyword Other Sum --- 3.Sum$keywords Vector Sum, Tree Sum.md | 100 ++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 4 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum.md b/3.Sum$keywords Vector Sum, Tree Sum.md index 9c38064..73f6e2b 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum.md @@ -1,4 +1,4 @@ -##3.Sum$keywords Vector Sum, Tree Sum +##3.Sum$keywords Vector Sum, Tree Sum, Other Sum ###*Vector Sum Vector Sum问题指的是从给定的数列中寻找和为定值的k个数(k可以为2,3,4以及任意不等)以及由此衍生的问题。对于有序序列的Sum(k=2)问题,可以使用两指针贪心算法;对于无序序列,可以排序再应用上述方法,也可以使用map方法。 @@ -166,6 +166,7 @@ public: ``` Ex4:[LeetCode:3sum-closest](http://oj.leetcode.com/problems/3sum-closest/) + 与前述题差异在于求解的是和与目标最接近的3个数。仍然应用Ex2中的通用解法,但在k==2的逻辑上略有改动。需要注意的是多了preSum和originT作为辅助实现,结果成立约束条件注意不要把target和originT混用。 ```cpp class Solution { @@ -335,14 +336,14 @@ public: ``` ###*Tree Sum -Tree Sum指在树节点中进行的有条件求和问题,对于树的遍历,最常用的方法莫过于DFS和BFS,以下例题展示这些方法是如何应用的。 +Tree Sum指在树节点中进行的有条件求和问题,对于树的遍历,基本思路是DFS或BFS,以下例题展示这些方法是如何应用的。 Ex7:[LeetCode:Binary Tree Maximum Path Sum](http://oj.leetcode.com/problems/binary-tree-maximum-path-sum/) -本题的解答写的比较繁琐,以后更新简洁解法。核心思想是递归函数返回的是当前节点的最大路径和P,注意这里所指的最大路径为当前节点到其叶子节点的单向子路径。同时使用一个全局变量或传引用变量记录路径最大值max,当前节点其能形成的最大子路径有四种情况: +本题的解答写的比较繁琐,以后更新简洁解法。核心思想是DFS递归函数返回的是当前节点的最大路径和P,注意这里所指的最大路径为当前节点到其叶子节点的简单子路径。同时使用一个全局变量或传引用变量记录路径最大值max,当前节点其能形成的最大子路径有四种情况: * 左孩子和右孩子都不存在,最大值为Vroot * 左孩子不存在,最大值为Vroot(如果P < 0)或Vroot+P -* 右孩子不存在,最大值为Vroot(如果P < 0)或Vroot+P < 0 +* 右孩子不存在,最大值为Vroot(如果P < 0)或Vroot+P * 左孩子和右孩子都存在,最大值为Vroot、Vroot+P、Vroot+P、Vroot+P+P情形之一 ```cpp @@ -391,3 +392,94 @@ public: } }; ``` +Ex8:[LeetCode:Sum Root to Leaf Numbers](http://oj.leetcode.com/problems/sum-root-to-leaf-numbers/) + +非常简单的一道题,利用DFS不断累加和值,直到叶子节点将其加入总和。 + +```cpp +class Solution { +public: + int total; + int sumNumbers(TreeNode *root) { + total = 0; + if(root == NULL) return 0; + sum(root, 0); + return total; + } + + void sum(TreeNode * root, int upToSum){ + if(root == NULL){ + return; + } + + if(root->left == NULL && root->right == NULL){ + total += upToSum * 10 + root->val; + return; + } + if(root->left == NULL){ + sum(root->right, upToSum * 10 + root->val); + return; + } + if(root->right == NULL){ + sum(root->left, upToSum * 10 + root->val); + return; + } + sum(root->left, upToSum * 10 + root->val); + sum(root->right, upToSum *10 + root->val); + return; + } +}; +``` + +Ex9:[LeetCode:Path Sum](http://oj.leetcode.com/problems/path-sum/) + +同样非常简单的一道题,DFS直到叶子节点,判断: +* 左孩子和右孩子都不存在,叶子节点,判等 +* 左孩子不存在,取决于b右孩子 +* 右孩子不存在,取决于b左孩子 +* 左孩子和右孩子都存在,取决于b左孩子&&b右孩子 + +```cpp +class Solution { +public: + bool hasPathSum(TreeNode *root, int sum) { + if(root == NULL) return false; + if(root->left == NULL && root->right == NULL){ + if(sum == root->val){ + return true; + }else{ + return false; + } + } + if(hasPathSum(root->left,sum-root->val)) return true; + if(hasPathSum(root->right,sum-root->val)) return true; + return false; + } +}; +``` + +Ex10:[LeetCode:Path Sum II](http://oj.leetcode.com/problems/path-sum-ii/) + +思路与Ex9一样,额外使用一个Stack来记录当前路径。 +```cpp +class Solution { +public: + vector > result; + vector temp; + vector > pathSum(TreeNode *root, int sum) { + if(root == NULL) return result; + temp.push_back(root->val); + if(root->left == NULL && root->right == NULL){ + if(root->val == sum){ + result.push_back(temp); + } + } + if(root->left != NULL) pathSum(root->left,sum-root->val); + if(root->right != NULL) pathSum(root->right,sum-root->val); + temp.pop_back(); + return result; + } +}; +``` + +###*Other Sum From c7aa734b0cdc956c95b1c3f6fd1cc46be74f6061 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 09:16:30 +0800 Subject: [PATCH 084/327] add keyword of Chapter 3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc9db8c..c641357 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Chapters ------------ 1.Permutations and Combinations$keywords Permutation, Combination 2.String dp and array dp$keywords dp -3.Sum$keywords Vector Sum, Tree Sum +3.Sum$keywords Vector Sum, Tree Sum, Other Sum 4.Search Array$keywords search Core contributors ------------ From a19ef1644758982cc312c3866e7d9a98e4be4519 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 09:51:08 +0800 Subject: [PATCH 085/327] Update 4.Search Array$keywords search.md update ex3 --- 4.Search Array$keywords search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index d2320ae..9998fc0 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -68,7 +68,7 @@ public class Solution { Ex3:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 -使用普通的比较时间复杂度是n方。这里介绍一种复杂度为nlogn的方法。该方法要借助二分排序,即将数组分为两部分分别排序。之后在对两个子数组进行merge的时候,去比较子数组1的当前元素和子数组2的当前元素,若1大于2,则说明1后面的元素都大于2,所以都为逆序对,将这些数加入结果集。 +使用普通的比较时间复杂度是n方。这里介绍一种复杂度为nlogn的方法。该方法要借助归并排序,即将数组分为两部分分别排序,然后merge。之后在对两个子数组进行merge的时候,去比较子数组1的当前元素和子数组2的当前元素,若1大于2,则说明1后面的元素都大于2,所以都为逆序对,将这些数加入结果集。 ```java public class Main { static long count = 0; From d0a7214ab466f55905363baa163d2d970e6c12de Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 09:57:05 +0800 Subject: [PATCH 086/327] add Ex11 --- ...d => 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md | 8 ++++++++ 1 file changed, 8 insertions(+) rename 3.Sum$keywords Vector Sum, Tree Sum.md => 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md (97%) diff --git a/3.Sum$keywords Vector Sum, Tree Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md similarity index 97% rename from 3.Sum$keywords Vector Sum, Tree Sum.md rename to 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index 73f6e2b..bfcaf39 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -483,3 +483,11 @@ public: ``` ###*Other Sum +该小节收录了一些不属于上两类的经典求和问题。 + +Ex11:[LeetCode:Maximum Subarray](http://oj.leetcode.com/problems/maximum-subarray/) + +经典问题,求解连续子数组最大和。核心思想是维护一个当前和值sum,如果sum比max大,则更新;如果sum<0,则对后面的子数组没有贡献,肯定不属于。 + + +Ex12: Maximum Rectangle From b78b614221ff433cd53e1b52a03b88fc45e8f032 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 10:00:51 +0800 Subject: [PATCH 087/327] Create 6.Tree transform and Tree search&keywords tree, transform, search.md --- ...transform and Tree search&keywords tree, transform, search.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 6.Tree transform and Tree search&keywords tree, transform, search.md diff --git a/6.Tree transform and Tree search&keywords tree, transform, search.md b/6.Tree transform and Tree search&keywords tree, transform, search.md new file mode 100644 index 0000000..8a1435f --- /dev/null +++ b/6.Tree transform and Tree search&keywords tree, transform, search.md @@ -0,0 +1 @@ +##*6.Tree transform and Tree search&keywords tree, transform, search From 5e2c01a1a5775d8e3fae3fcd79b15dd727d33fd7 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 10:10:21 +0800 Subject: [PATCH 088/327] add anchors --- 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index bfcaf39..932d594 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -1,4 +1,5 @@ -##3.Sum$keywords Vector Sum, Tree Sum, Other Sum +##3.Sum$keywords [Vector Sum](#VectorSumAnchor), [Tree Sum](#TreeSumAnchor), [Other Sum](#OtherSumAnchor) + ###*Vector Sum Vector Sum问题指的是从给定的数列中寻找和为定值的k个数(k可以为2,3,4以及任意不等)以及由此衍生的问题。对于有序序列的Sum(k=2)问题,可以使用两指针贪心算法;对于无序序列,可以排序再应用上述方法,也可以使用map方法。 @@ -334,6 +335,7 @@ public: }*/ }; ``` + ###*Tree Sum Tree Sum指在树节点中进行的有条件求和问题,对于树的遍历,基本思路是DFS或BFS,以下例题展示这些方法是如何应用的。 @@ -481,7 +483,7 @@ public: } }; ``` - + ###*Other Sum 该小节收录了一些不属于上两类的经典求和问题。 From 048c25e9cb321fed9b9ea17b97542c040de530ef Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 10:11:15 +0800 Subject: [PATCH 089/327] Update 6.Tree transform and Tree search&keywords tree, transform, search.md Ex1 updated --- ...search&keywords tree, transform, search.md | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/6.Tree transform and Tree search&keywords tree, transform, search.md b/6.Tree transform and Tree search&keywords tree, transform, search.md index 8a1435f..52e6138 100644 --- a/6.Tree transform and Tree search&keywords tree, transform, search.md +++ b/6.Tree transform and Tree search&keywords tree, transform, search.md @@ -1 +1,69 @@ -##*6.Tree transform and Tree search&keywords tree, transform, search +##*6.Tree transform and Tree search&keywords tree, transform, search + +Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 +要求不能创建任何新的结点,只调整指针的指向。 + +该方法采用中序遍历的思想,每次中序遍历时,传入两个指针,分别指向子链表的头尾,之后将两边的子链表和当前节点穿成一个新链表返回。 +```cpp +#include +#include +using namespace std; +struct TreeNode{ + int val; + TreeNode* left; + TreeNode* right; + TreeNode(int x) : val(x),left(NULL),right(NULL){} +}; + +TreeNode* buildTree(){ + TreeNode* node1 = new TreeNode(1); + TreeNode* node2 = new TreeNode(2); + TreeNode* node3 = new TreeNode(3); + TreeNode* node4 = new TreeNode(4); + TreeNode* node5 = new TreeNode(5); + TreeNode* node6 = new TreeNode(6); + node4->left = node2; + node4->right = node5; + node2->left = node1; + node2->right = node3; + node5->right = node6; + + return node4; +} + +void visit(TreeNode* node, TreeNode *& head, TreeNode *& tail){ + if(node==NULL){ + head=NULL; + tail=NULL; + return; + } + TreeNode* l = NULL; + TreeNode* r = NULL; + visit(node->left,head,l); + visit(node->right,r,tail); + if(l!=NULL){ + l->right=node; + node->left=l; + } + else + head=node; + if(r!=NULL){ + r->left=node; + node->right=r; + } + else + tail=node; +} + +int main(){ + TreeNode* head = NULL; + TreeNode* tail = NULL; + TreeNode* root = buildTree(); + visit(root,head,tail); + for(TreeNode* node=head;node!=NULL;node=node->right) + printf("%d ",node->val); + + system("pause"); + return 0; +} +``` From d0cf234faf43839c9a516ec467562c441fce6487 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 10:15:08 +0800 Subject: [PATCH 090/327] add anchors --- ...ons and Combinations$keywords Permutation, Combination.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index 0ddd70f..ec0e304 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -1,4 +1,5 @@ -##1.Permutations and Combinations$keywords Permutation, Combination +##1.Permutations and Combinations$keywords [Permutation](#PermutationAnchor), [Combination](#CombinationAnchor) + ###*Permutation 一般来说有两种解题思路,一种是利用递归生成所有的Permutation,另一种是利用求上一个/下一个Permutation来求出所有的Permutation。该题有可分为有重复和无重复元素的情况。求上一个/下一个的方法适用于有重复和无重复的情况,不需要做适应化修改 而递归方法在有重复元素的情况下需要修改为对当次递归相同的元素做跳过处理。 @@ -174,7 +175,7 @@ public: } }; ``` - + ###*Combination 对于Combination通常的解法是递归,与Permutation不同的地方在于每个递归过程只需考虑是否选当前数字,这是Combination由位置无关特性决定的。 From 0e3c96c823de3cabcdfb08994152eeb8c3545e22 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 10:19:00 +0800 Subject: [PATCH 091/327] finish Ex11 --- ...eywords Vector Sum, Tree Sum, Other Sum.md | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index 932d594..d4aa4aa 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -489,7 +489,29 @@ public: Ex11:[LeetCode:Maximum Subarray](http://oj.leetcode.com/problems/maximum-subarray/) -经典问题,求解连续子数组最大和。核心思想是维护一个当前和值sum,如果sum比max大,则更新;如果sum<0,则对后面的子数组没有贡献,肯定不属于。 - +经典问题,求解连续子数组最大和。核心思想是维护一个当前和值sum,如果sum比max大,则更新;如果sum小于0,则对后面的子数组没有贡献,肯定不属于可行解的一部分,舍去,最终求出结果。 +```cpp +class Solution { +public: + int maxSubArray(int A[], int n) { + int sum = 0, max = INT_MIN; + for(int i = 0; i <= n-1; i++){ + sum += A[i]; + if(sum > max){ + max = sum; + } + if(sum < 0){ + sum = 0; + } + } + return max; + } +}; +``` Ex12: Maximum Rectangle + + +```cpp + +``` From 95da819fe8e6a3488f18a26965aa64c1d096136d Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 10:23:04 +0800 Subject: [PATCH 092/327] Ex2 updated --- ...search&keywords tree, transform, search.md | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/6.Tree transform and Tree search&keywords tree, transform, search.md b/6.Tree transform and Tree search&keywords tree, transform, search.md index 52e6138..8c34fa2 100644 --- a/6.Tree transform and Tree search&keywords tree, transform, search.md +++ b/6.Tree transform and Tree search&keywords tree, transform, search.md @@ -67,3 +67,52 @@ int main(){ return 0; } ``` + +Ex2:[Leetcode:Binary Tree Zigzag Level Order Traversal](http://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) + +首先,既然是层次遍历,肯定需要用到队列。在对每一层进行访问的时候,首先记录队列中的第一个节点和最后一个节点,这是上一层的首尾节点,然后按不同的方向访问每个节点的左右子节点,访问后将该节点弹出队列,这样就能保证加入队列的节点也是有序的。对一层的访问结束后,将方向反转。 +```java +import java.util.ArrayList; +import java.util.LinkedList; + +public class Solution { + public ArrayList> zigzagLevelOrder(TreeNode root) { + ArrayList> result = new ArrayList>(); + if (root == null) + return result; + LinkedList queue = new LinkedList(); + queue.add(root); + boolean flag = true; + while (!queue.isEmpty()) { + ArrayList tmp = new ArrayList(); + if (flag) { + TreeNode end = queue.getLast(); + TreeNode node = null; + while (node != end) { + node = queue.pollFirst(); + tmp.add(node.val); + if (node.left != null) + queue.add(node.left); + if (node.right != null) + queue.add(node.right); + } + } else { + TreeNode start = queue.getFirst(); + TreeNode node = null; + while (node != start) { + node = queue.pollLast(); + tmp.add(node.val); + if (node.right != null) + queue.addFirst(node.right); + if (node.left != null) + queue.addFirst(node.left); + } + } + flag = !flag; + result.add(tmp); + } + return result; + } +} +``` + From 475cdd5eaf71951b6510eac8ea234bca411afeb1 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 10:25:14 +0800 Subject: [PATCH 093/327] add chapter 6 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c641357..5f4f21d 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ Chapters 2.String dp and array dp$keywords dp 3.Sum$keywords Vector Sum, Tree Sum, Other Sum 4.Search Array$keywords search +5.NA +6.Tree transform and Tree search&keywords tree, transform, search Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From e20a4725c9f3138f833b8078cee2cf6441b88dc9 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 10:29:25 +0800 Subject: [PATCH 094/327] add links of Chapters --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5f4f21d..a255184 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ -1.Permutations and Combinations$keywords Permutation, Combination -2.String dp and array dp$keywords dp -3.Sum$keywords Vector Sum, Tree Sum, Other Sum -4.Search Array$keywords search -5.NA +1.[Permutations and Combinations](/1.Permutations and Combinations$keywords Permutation, Combination.md)$keywords Permutation, Combination +2.[String dp and array dp](2.String dp and Array dp$keywords dp.md)$keywords dp +3.[Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)$keywords Vector Sum, Tree Sum, Other Sum +4.[Search Array](4.Search Array$keywords search.md)$keywords search +5.NA 6.Tree transform and Tree search&keywords tree, transform, search Core contributors ------------ From 748f658807d674618813a57be4dda6cc0888de1a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 10:30:19 +0800 Subject: [PATCH 095/327] Create 5.NA --- 5.NA | 1 + 1 file changed, 1 insertion(+) create mode 100644 5.NA diff --git a/5.NA b/5.NA new file mode 100644 index 0000000..8ad1dfb --- /dev/null +++ b/5.NA @@ -0,0 +1 @@ +//TODO From 22d71efb4bba0e96ea8a9cf0a128c05e155cdb16 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 10:42:36 +0800 Subject: [PATCH 096/327] update ex3 --- ...search&keywords tree, transform, search.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/6.Tree transform and Tree search&keywords tree, transform, search.md b/6.Tree transform and Tree search&keywords tree, transform, search.md index 8c34fa2..9f9043c 100644 --- a/6.Tree transform and Tree search&keywords tree, transform, search.md +++ b/6.Tree transform and Tree search&keywords tree, transform, search.md @@ -116,3 +116,27 @@ public class Solution { } ``` +Ex3:树中两个结点的最低公共祖先:给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。 + +这道题有一个简单的方法。使用的还是中序遍历方法,返回最低公共祖先。每当遍历到一个节点时,有以下几种情况: +* 当前节点等于任一个给定节点。返回当前节点。 +* 若不是,若遍历完左节点返回null,说明最低公共祖先在右边 +* 若右节点返回null,说明最低公共祖先在左边 +* 若都不为null,说明当前节点为最低公共祖先 + +```cpp +TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { + if (root == NULL) + return NULL; + if (X == root || Y == root) + return root; + TreeNode * left = getLCA(root->m_pLeft, X, Y); + TreeNode * right = getLCA(root->m_pRight, X, Y); + if (left == NULL) + return right; + else if (right == NULL) + return left; + else + return root; +} +``` From 0c1fa3a22cf56260fb2bac163ba4c367e580d5ec Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 11:09:32 +0800 Subject: [PATCH 097/327] Ex4 updated --- ...search&keywords tree, transform, search.md | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/6.Tree transform and Tree search&keywords tree, transform, search.md b/6.Tree transform and Tree search&keywords tree, transform, search.md index 9f9043c..adf7d15 100644 --- a/6.Tree transform and Tree search&keywords tree, transform, search.md +++ b/6.Tree transform and Tree search&keywords tree, transform, search.md @@ -3,7 +3,7 @@ Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 -该方法采用中序遍历的思想,每次中序遍历时,传入两个指针,分别指向子链表的头尾,之后将两边的子链表和当前节点穿成一个新链表返回。 +该方法采用后序遍历的思想,每次后序遍历时,传入两个指针,分别指向子链表的头尾,之后将两边的子链表和当前节点穿成一个新链表返回。 ```cpp #include #include @@ -118,7 +118,7 @@ public class Solution { Ex3:树中两个结点的最低公共祖先:给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。 -这道题有一个简单的方法。使用的还是中序遍历方法,返回最低公共祖先。每当遍历到一个节点时,有以下几种情况: +这道题有一个简单的方法。使用的是后序遍历方法,返回最低公共祖先。每当遍历到一个节点时,有以下几种情况: * 当前节点等于任一个给定节点。返回当前节点。 * 若不是,若遍历完左节点返回null,说明最低公共祖先在右边 * 若右节点返回null,说明最低公共祖先在左边 @@ -140,3 +140,40 @@ TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { return root; } ``` + +Ex4:[Leetcode:Recover Binary Search Tree](http://oj.leetcode.com/problems/recover-binary-search-tree/) + +本题采用中序遍历。对于二叉排序树来说,中序遍历序列应该是单调递增的。 +* 若被交换的两个元素在原本中序序列中相邻,那么对当前的树中序遍历只会出现一次异常,即后面的数小于前面的数,那将这两个数交换即可 +* 若不相邻,则会出现两次异常。这种情况下我们要记录第一次异常中的首和第二次异常中的尾,将两个数交换。 +```java +public class Solution { + TreeNode pre; + TreeNode n1; + TreeNode n2; + + public void recoverTree(TreeNode root) { + visit(root); + if (n1 != null) { + int tmp = n1.val; + n1.val = n2.val; + n2.val = tmp; + } + } + + public void visit(TreeNode root) { + if (root == null) + return; + visit(root.left); + if (pre == null) + pre = root; + else if (root.val < pre.val) { + n2 = root; + if (n1 == null) + n1 = pre; + } + pre = root; + visit(root.right); + } +} +``` From 5575c685bd65664015159ae1abed16151d642208 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 13:58:00 +0800 Subject: [PATCH 098/327] update name --- ... transform and Tree visit&keywords tree, transform, visit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename 6.Tree transform and Tree search&keywords tree, transform, search.md => 6.Tree transform and Tree visit&keywords tree, transform, visit.md (98%) diff --git a/6.Tree transform and Tree search&keywords tree, transform, search.md b/6.Tree transform and Tree visit&keywords tree, transform, visit.md similarity index 98% rename from 6.Tree transform and Tree search&keywords tree, transform, search.md rename to 6.Tree transform and Tree visit&keywords tree, transform, visit.md index adf7d15..53aa6d9 100644 --- a/6.Tree transform and Tree search&keywords tree, transform, search.md +++ b/6.Tree transform and Tree visit&keywords tree, transform, visit.md @@ -1,4 +1,4 @@ -##*6.Tree transform and Tree search&keywords tree, transform, search +##*6.Tree transform and Tree search&keywords tree, transform, visit Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 From acea7f5a9f578d594c6de165f792c09f2906d46b Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 13:59:59 +0800 Subject: [PATCH 099/327] Update 6.Tree transform and Tree visit&keywords tree, transform, visit.md --- ... transform and Tree visit&keywords tree, transform, visit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/6.Tree transform and Tree visit&keywords tree, transform, visit.md b/6.Tree transform and Tree visit&keywords tree, transform, visit.md index 53aa6d9..a8efd53 100644 --- a/6.Tree transform and Tree visit&keywords tree, transform, visit.md +++ b/6.Tree transform and Tree visit&keywords tree, transform, visit.md @@ -1,4 +1,4 @@ -##*6.Tree transform and Tree search&keywords tree, transform, visit +##*6.Tree transform and Tree visit&keywords tree, transform, visit Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 From caf8037df076a9a14ee95a835564acd8395314c6 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 15:28:01 +0800 Subject: [PATCH 100/327] create Graph&keywords graph.md --- 5.Graph&keywords graph.md | 1 + 5.NA | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 5.Graph&keywords graph.md delete mode 100644 5.NA diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md new file mode 100644 index 0000000..8cfa0c7 --- /dev/null +++ b/5.Graph&keywords graph.md @@ -0,0 +1 @@ +##*5.Graph&keywords graph diff --git a/5.NA b/5.NA deleted file mode 100644 index 8ad1dfb..0000000 --- a/5.NA +++ /dev/null @@ -1 +0,0 @@ -//TODO From 47c37f0b8d8a7ac9ef21d64ca1a63fbd9c22600d Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 15:29:41 +0800 Subject: [PATCH 101/327] update name --- ...sform, visit.md => 6.Tree&keywords tree, transform, visit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename 6.Tree transform and Tree visit&keywords tree, transform, visit.md => 6.Tree&keywords tree, transform, visit.md (98%) diff --git a/6.Tree transform and Tree visit&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md similarity index 98% rename from 6.Tree transform and Tree visit&keywords tree, transform, visit.md rename to 6.Tree&keywords tree, transform, visit.md index a8efd53..9da65ef 100644 --- a/6.Tree transform and Tree visit&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -1,4 +1,4 @@ -##*6.Tree transform and Tree visit&keywords tree, transform, visit +##*6.Tree&keywords tree, transform, visit Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 From bb0aa3b7bd435d30a4091c5828fd4bc65d53ee31 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 15:34:24 +0800 Subject: [PATCH 102/327] Update Ex1 --- 5.Graph&keywords graph.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 8cfa0c7..7b6fe14 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -1 +1,36 @@ ##*5.Graph&keywords graph + +Ex1:prim:求一个图的最小生成树 + +标准的prim算法,用邻接矩阵来表示图,用一个数组来表示最小生成树 +```java +public int prim() { + boolean[] in = new boolean[num + 1]; + in[1] = true; + int max = 0; + while (!allin(in)) { + int min = Integer.MAX_VALUE; + int target = 0; + for (int i = 1; i <= num; i++) + if (in[i]) + for (int j = 1; j <= num; j++) + if (i != j && !in[j] && dis[i][j] < min) { + min = dis[i][j]; + target = j; + } + in[target] = true; + if (min > max) + max = min; + } + + return max; + } + + public boolean allin(boolean[] in) { + for (boolean a : in) + if (!a) + return false; + + return true; + } +``` From f53a069ab236b4241e8c701c1027630dd5de38fe Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 15:35:27 +0800 Subject: [PATCH 103/327] Update Ex1 --- 5.Graph&keywords graph.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 7b6fe14..7c589b3 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -4,7 +4,33 @@ Ex1:prim:求一个图的最小生成树 标准的prim算法,用邻接矩阵来表示图,用一个数组来表示最小生成树 ```java -public int prim() { + +public class Main { + int num; + int[][] dis; + + public Main(int num, int[][] dis) { + this.num = num; + this.dis = dis; + } + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n = in.nextInt(); + while (n-- != 0) { + int num = in.nextInt(); + int[][] dis = new int[num + 1][num + 1]; + for (int i = 1; i <= num; i++) + for (int j = 1; j <= num; j++) + dis[i][j] = in.nextInt(); + + Main m = new Main(num, dis); + int result = m.prim(); + System.out.println(result); + } + } + + public int prim() { boolean[] in = new boolean[num + 1]; in[1] = true; int max = 0; @@ -33,4 +59,5 @@ public int prim() { return true; } +} ``` From e169210f5380fd1972d4338b97bd4a53da14f1f9 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 16:05:04 +0800 Subject: [PATCH 104/327] update ex2 --- 5.Graph&keywords graph.md | 71 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 7c589b3..937a278 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -1,6 +1,6 @@ ##*5.Graph&keywords graph -Ex1:prim:求一个图的最小生成树 +Ex1:Prim:求一个图的最小生成树 标准的prim算法,用邻接矩阵来表示图,用一个数组来表示最小生成树 ```java @@ -61,3 +61,72 @@ public class Main { } } ``` + +Ex2:Dijkstra:求某个定点到其他所有顶点的单源最短路径 + +标准的Dijkstra算法,用邻接矩阵来表示图,每次加入一个点并更新最小距离 +```java +public class Dijkstra { + static int M = 10000; + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[][] weight1 = {// 邻接矩阵 + { 0, 3, 2000, 7, M }, { 3, 0, 4, 2, M }, { M, 4, 0, 5, 4 }, + { 7, 2, 5, 0, 6 }, { M, M, 4, 6, 0 } }; + + int[][] weight2 = { { 0, 10, M, 30, 100 }, { M, 0, 50, M, M }, + { M, M, 0, M, 10 }, { M, M, 20, 0, 60 }, { M, M, M, M, 0 } }; + int start = 0; + int[] shortPath = Dijsktra(weight1, start); + + for (int i = 0; i < shortPath.length; i++) + System.out.println("从" + start + "出发到" + i + "的最短距离为:" + + shortPath[i]); + } + + public static int[] Dijsktra(int[][] weight, int start) { + // 接受一个有向图的权重矩阵,和一个起点编号start(从0编号,顶点存在数组中) + // 返回一个int[] 数组,表示从start到它的最短路径长度 + int n = weight.length; // 顶点个数 + int[] shortPath = new int[n]; // 存放从start到其他各点的最短路径 + String[] path = new String[n]; // 存放从start到其他各点的最短路径的字符串表示 + for (int i = 0; i < n; i++) + path[i] = new String(start + "-->" + i); + int[] visited = new int[n]; // 标记当前该顶点的最短路径是否已经求出,1表示已求出 + + // 初始化,第一个顶点求出 + shortPath[start] = 0; + visited[start] = 1; + + for (int count = 1; count <= n - 1; count++) // 要加入n-1个顶点 + { + int k = -1; // 选出一个距离初始顶点start最近的未标记顶点 + int dmin = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (visited[i] == 0 && weight[start][i] < dmin) { + dmin = weight[start][i]; + k = i; + } + } + // System.out.println("k="+k); + // 将新选出的顶点标记为已求出最短路径,且到start的最短路径就是dmin + shortPath[k] = dmin; + visited[k] = 1; + // 以k为中间点,修正从start到未访问各点的距离 + for (int i = 0; i < n; i++) { + if (visited[i] == 0 + && weight[start][k] + weight[k][i] < weight[start][i]) { + weight[start][i] = weight[start][k] + weight[k][i]; + path[i] = path[k] + "-->" + i; + } + } + } + for (int i = 0; i < n; i++) + System.out.println("从" + start + "出发到" + i + "的最短路径为:" + path[i]); + System.out.println("====================================="); + + return shortPath; + } +} +``` From 4129af1e13f58e60ca98e7dd6d6d9654a13a2230 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 16:05:17 +0800 Subject: [PATCH 105/327] update links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a255184..20c3bd0 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路 Chapters ------------ -1.[Permutations and Combinations](/1.Permutations and Combinations$keywords Permutation, Combination.md)$keywords Permutation, Combination +1.[Permutations and Combinations](1.Permutations and Combinations$keywords Permutation, Combination.md)$keywords Permutation, Combination 2.[String dp and array dp](2.String dp and Array dp$keywords dp.md)$keywords dp 3.[Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)$keywords Vector Sum, Tree Sum, Other Sum 4.[Search Array](4.Search Array$keywords search.md)$keywords search -5.NA -6.Tree transform and Tree search&keywords tree, transform, search +5.[Graph](5.Graph&keywords graph.md)$keywords graph +6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 6300c5d50afb4b7b458b4df4a658979b8938d87f Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 16:09:39 +0800 Subject: [PATCH 106/327] update ex3 --- 5.Graph&keywords graph.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 937a278..1030c8e 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -130,3 +130,28 @@ public class Dijkstra { } } ``` + +Ex3:Floyd:求每一个顶点到其他所有定点的最短长度 + +标准的Floyd算法。 +```java +public class Floyd { + + public double[][] matrix; + + public Floyd(double[][] mat) { + matrix = mat; + } + + public double[][] doFloyd() { + int size = InitMatrix.size; + for (int k = 1; k <= size; k++) + for (int i = 1; i <= size; i++) + for (int j = 1; j <= size; j++) + if (matrix[i][j] > matrix[i][k] + matrix[k][j]) + matrix[i][j] = matrix[i][k] + matrix[k][j]; + return matrix; + } +} +``` + From 57a3e64d5c8245931f059c2da440fa2a44ee55fc Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 16:17:47 +0800 Subject: [PATCH 107/327] update ex4 --- 5.Graph&keywords graph.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 1030c8e..6cbf5d5 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -155,3 +155,42 @@ public class Floyd { } ``` +Ex4:四色定理:用颜色去标记图的所有顶点,要求相邻的顶点颜色不同,问最少多少种颜色。 + +用数字代表颜色。遍历图,对于每个节点,记录与它相邻节点的颜色,然后选出这些颜色中不包含的、数字最小的颜色,涂在当前节点。 +```java +public class Solution { + public void FourColor(String[] ss) { + int len = ss.length; + boolean[][] map = new boolean[len + 1][27]; + for (String s : ss) + for (int i = 2; i < s.length(); i++) + map[s.charAt(0) - 'A' + 1][s.charAt(i) - 'A' + 1] = true; + int max = 0; + + int[] color = new int[27]; + for (int i = 1; i <= len; i++) { + boolean[] visit = new boolean[len + 1]; + for (int j = 1; j <= len; j++) + if (map[i][j]) + if (color[j] != 0) + visit[color[j]] = true; + for (int j = 1; j <= len; j++) + if (!visit[j]) { + color[i] = j; + max = Math.max(max, j); + break; + } + } + + System.out.println(max); + } + + public static void main(String[] args) { + Solution m = new Solution(); + // String[] ss = { "A:BCD", "B:ACD", "C:ABD", "D:ABC" }; + String[] ss = { "A:BC", "B:ACD", "C:ABD", "D:BC" }; + m.FourColor(ss); + } +} +``` From 70f2279335057eb01af620146fa1a820527fab77 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 17:03:29 +0800 Subject: [PATCH 108/327] update ex5 --- 5.Graph&keywords graph.md | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 6cbf5d5..a8870d9 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -194,3 +194,55 @@ public class Solution { } } ``` + +Ex5:[Leetcode:Palindrome Partitioning II](http://oj.leetcode.com/problems/palindrome-partitioning-ii/) + +此题中先用到了dp标记(详见String dp and array dp),然后用Dijkstra算法计算从0到末尾的最短距离 +```java +public class Solution { + public int minCut(String s) { + //回文串的判定二维数组 + boolean[][] isPalindrome = new boolean[s.length()+1][s.length()+1]; + for (int i=0; i Date: Mon, 24 Feb 2014 17:05:53 +0800 Subject: [PATCH 109/327] update ex6 --- 5.Graph&keywords graph.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index a8870d9..8512c9c 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -246,3 +246,7 @@ public class Solution { } } ``` + +Ex6:求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边, +有向图不再连通 + From 516188ca9882e30b9ed5dc141c8841e4ba8e37cb Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 20:02:33 +0800 Subject: [PATCH 110/327] Create 0.Clever Problems --- 0.Clever Problems | 1 + 1 file changed, 1 insertion(+) create mode 100644 0.Clever Problems diff --git a/0.Clever Problems b/0.Clever Problems new file mode 100644 index 0000000..8b45841 --- /dev/null +++ b/0.Clever Problems @@ -0,0 +1 @@ +##Clever Problems From 72db8f48b261bdb22279a9819c55f99e199f2089 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 20:08:12 +0800 Subject: [PATCH 111/327] add chapter 0 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 20c3bd0..9db5e91 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,11 @@ AlgorithmNote ============= Introduction ------------ -AlgorithmNote是一个主题分类的用于记录、整理和分享算法思路和解法,主要对相同和相似的题目的解题思路做归类分析,文中涉及的题目来自Leetcode,微软100题,剑指offer及各大算法博客等。 +AlgorithmNote是一个按照主题分类的用于记录、整理和分享算法思路和解法Github项目,文中涉及的题目来自Leetcode、微软100题、编程之美、OJ、剑指offer及各大算法博客等。 Chapters ------------ +0.[Tricky Problems](0.Tricky Problems) 1.[Permutations and Combinations](1.Permutations and Combinations$keywords Permutation, Combination.md)$keywords Permutation, Combination 2.[String dp and array dp](2.String dp and Array dp$keywords dp.md)$keywords dp 3.[Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)$keywords Vector Sum, Tree Sum, Other Sum From 78d28d2d15bd96f01d90e0b640c0f048f0850f56 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 20:09:19 +0800 Subject: [PATCH 112/327] update title --- 0.Clever Problems | 1 - 0.Tricky Problems.md | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 0.Clever Problems create mode 100644 0.Tricky Problems.md diff --git a/0.Clever Problems b/0.Clever Problems deleted file mode 100644 index 8b45841..0000000 --- a/0.Clever Problems +++ /dev/null @@ -1 +0,0 @@ -##Clever Problems diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md new file mode 100644 index 0000000..a231a59 --- /dev/null +++ b/0.Tricky Problems.md @@ -0,0 +1 @@ +##Tricky Problems From 913355b28bb7ba24d9a9d6f1956ccbefc3f21351 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 20:12:42 +0800 Subject: [PATCH 113/327] add rules of Tricky Problems --- 0.Tricky Problems.md | 1 + 1 file changed, 1 insertion(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index a231a59..19f0aa8 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -1 +1,2 @@ ##Tricky Problems +本章用于收录一些微妙、技巧性较强的问题。一般的,问题所属分类模糊或同类问题较少会导致该问题被收录在Tricky Problems,在条件成熟的情况下可以被移出至新的章节。 From a48a530c53a49090746943f28ebe09e27c1537a9 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 20:54:59 +0800 Subject: [PATCH 114/327] finish Ex12 --- ...eywords Vector Sum, Tree Sum, Other Sum.md | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index d4aa4aa..96fc2b9 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -1,5 +1,5 @@ ##3.Sum$keywords [Vector Sum](#VectorSumAnchor), [Tree Sum](#TreeSumAnchor), [Other Sum](#OtherSumAnchor) - + ###*Vector Sum Vector Sum问题指的是从给定的数列中寻找和为定值的k个数(k可以为2,3,4以及任意不等)以及由此衍生的问题。对于有序序列的Sum(k=2)问题,可以使用两指针贪心算法;对于无序序列,可以排序再应用上述方法,也可以使用map方法。 @@ -511,7 +511,64 @@ public: Ex12: Maximum Rectangle +求解一个二维数组A[N][M]拥有最大和值的子数组。如 +1 -1 -1 +-1 5 7 +-1 6 8 +结果子数组为 +5 7 +6 8 +和值为26 -```cpp +考虑将二维数组降维为一维处理,可以获得O(N2M)的时间复杂度。具体做法是使用s,e作为上下界确定矩形的高,将s和e之间的**一列元素的和**等同于一维问题的一个元素。对于特定的s和e,应用一维的O(n)算法求出特定s和e情形下的最大值;穷举s和e的组合,求出全局的最大值。使用dp的方法事先求解列和,dp[i][j]表示第j列中第0个至第i个的和值。 +```cpp +int solution(vector > input){ + if(input.empty()) return INT_MIN; + if(input[0].empty()) return INT_MIN; + + int ret = INT_MIN; + int row = input.size(), col = input[0].size(); + + int dp[row][col]; + for(int i = 0; i <= row-1; i++){ + for(int j = 0; j <= col-1;j++){ + if(i == 0){ + dp[i][j] = input[i][j]; + }else{ + dp[i][j] = input[i][j] + dp[i-1][j]; + } + } + } + + int A[col]; + for(int s = 0; s <= row-1; s++){ + for(int e = s; e <= row-1; e++){ + for(int k = 0; k <= col-1; k++){ + if(s == 0){ + A[k] = dp[e][k]; + }else{ + A[k] = dp[e][k] - dp[s-1][k]; + } + } + int temp = MaxSubArray(A, col); + ret = temp > ret?temp:ret; + } + } + return ret; +} + +int MaxSubArray(int A[], int n){ + int sum = 0, max = INT_MIN; + for(int i = 0; i <= n-1; i++){ + sum += A[i]; + if(sum > max){ + max = sum; + } + if(sum < 0){ + sum = 0; + } + } + return max; +} ``` From d16c0c4909c1ce74163ff472a5229021d6757d03 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 24 Feb 2014 20:59:01 +0800 Subject: [PATCH 115/327] revise some details --- 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index 96fc2b9..c5909af 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -509,7 +509,7 @@ public: }; ``` -Ex12: Maximum Rectangle +Ex12: Maximum SubMatrix 求解一个二维数组A[N][M]拥有最大和值的子数组。如 1 -1 -1 @@ -523,7 +523,7 @@ Ex12: Maximum Rectangle 考虑将二维数组降维为一维处理,可以获得O(N2M)的时间复杂度。具体做法是使用s,e作为上下界确定矩形的高,将s和e之间的**一列元素的和**等同于一维问题的一个元素。对于特定的s和e,应用一维的O(n)算法求出特定s和e情形下的最大值;穷举s和e的组合,求出全局的最大值。使用dp的方法事先求解列和,dp[i][j]表示第j列中第0个至第i个的和值。 ```cpp -int solution(vector > input){ +int Solution(vector > input){ if(input.empty()) return INT_MIN; if(input[0].empty()) return INT_MIN; From ec9cd2ce8167c63deb38628dabb3e92141235561 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 21:11:27 +0800 Subject: [PATCH 116/327] update ex6 --- 5.Graph&keywords graph.md | 91 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 8512c9c..52ec560 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -250,3 +250,94 @@ public class Solution { Ex6:求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边, 有向图不再连通 +//思路加载中。。。 +```cpp +#include +using namespace std; +int times=1,low[1000],dfn[1000]; + +int stack[1000],top=0; + +bool instack[1000]={false}; + +struct LIST +{ + int v; + LIST *next; +}; + +LIST *head[1000]={NULL}; + +int min(int a,int b) +{ + if(anext) /*遍历V能直接到达的点*/ + if(!dfn[p->v]) /*如果v的邻接点没有入过栈*/ + { + tarjan(p->v); + low[v]=min(low[v],low[p->v]); /*如果v能直接到达的这个点没在栈中,v的最早祖先为他们中的较小值*/ + } + else if(instack[p->v]) /*如果在栈中*/ + low[v]=min(low[v],dfn[p->v]); /*如果在栈中,则v的最早祖先是他的序号和那个点的序号较小的*/ + + if(dfn[v]==low[v]) /*如果dfn[v]和low[v]相等,则说明v点是其所属强连通分支DFS遍历起点,这个强连通分支说有点都在v点之上*/ + { + cout<<"{ "; + do + { + v=stack[--top]; + instack[v]=false; + cout<>n; + + memset(dfn,0,sizeof(char)*4000); + for(i=1;i<=n;i++) + { + cout<>m; + cout<<"输入每个邻接点编号"; + LIST *rear=head[i]; + for(j=0;jnext=new LIST; + rear=rear->next; + } + rear->next=NULL; + cin>>rear->v; + } + } + + for(i=1;i<=n;i++) + if(!dfn[i]) /*如果i没有入过栈*/ + tarjan(i); + + system("pause"); + return 0; +} +``` From 8e82d3457f7cd6bf5e7983798bc89d700ca1cc31 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 24 Feb 2014 22:11:20 +0800 Subject: [PATCH 117/327] update ex6 --- 5.Graph&keywords graph.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 52ec560..38e85c2 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -250,7 +250,11 @@ public class Solution { Ex6:求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边, 有向图不再连通 -//思路加载中。。。 +Tarjan算法:Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。 +定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。 +对于树枝边(u,v),有low[u]=min(low[u],low[v]). +对于后向边(u,v)(指向在当前栈中节点的边),有low[u]=min(low[u],dfn[v]). +当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。 ```cpp #include using namespace std; From 609f59551d34c495a26240fcffd46c43a0cec1d9 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 25 Feb 2014 09:22:57 +0800 Subject: [PATCH 118/327] finish Ex13 --- ...eywords Vector Sum, Tree Sum, Other Sum.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index c5909af..023f905 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -572,3 +572,35 @@ int MaxSubArray(int A[], int n){ return max; } ``` +Ex13:Count number of 1 from 1 to n + +统计从1到n共n个十进制整数中包含1的总数,如输入n=11,统计结果为4(1,10,11)。 + +核心思路是按位统计1的个数,以一个例子来说明规则是如何被应用的。 +* 对于十进制数12035的百位上1的个数,由于百位上的数是'0',故只由百位前面的“高位”决定 + + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) +* 对于十进制数12135,由于百位上的数是'1',故由百位前面的“高位”和百位后面的“低位”共同决定 + + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) + + 35 + 1个(12100~12135) +* 对于十进制数12512,由于百位上的数是'5',故由百位前面的“高位”决定 + + (12 + 1) * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199,12100~12199) +由此可以看出统计规则主要是在统计第x位时,获得x的“高位”和低位,并根据x与1的关系分类计算,代码如下。 + +```cpp +int countOnes(int n){ + int ret = 0, factor = 1; + int higher = 0, cur = 0, lower = 0; + while(n / factor != 0){//n == 12135 + higher = n/(factor*10);//12, when factor == 100 + cur = (n/factor)%10;//1, when factor == 100 + lower = n%factor;//35, when factor == 100 + switch(cur){ + case 0: ret += higher * factor; break; + case 1: ret += higher * factor + lower + 1; break; + default: ret += (higher + 1) * factor; break; + } + factor *= 10; + } + return ret; +} +``` From ddf8038a7cabbe0c9f314176796935526fbe3cda Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 25 Feb 2014 09:26:30 +0800 Subject: [PATCH 119/327] revise composing --- 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index 023f905..6174b48 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -574,16 +574,15 @@ int MaxSubArray(int A[], int n){ ``` Ex13:Count number of 1 from 1 to n -统计从1到n共n个十进制整数中包含1的总数,如输入n=11,统计结果为4(1,10,11)。 - -核心思路是按位统计1的个数,以一个例子来说明规则是如何被应用的。 -* 对于十进制数12035的百位上1的个数,由于百位上的数是'0',故只由百位前面的“高位”决定 +统计从1到n共n个十进制整数中包含1的总数,如输入n=11,统计结果为4(1,10,11)。 +核心思路是按位统计1的个数,以一个例子来说明规则是如何被应用的。统计百位上1的个数: +* 对于十进制数12035,由于百位上的数是'0',故只由百位前面的“高位”决定 + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) * 对于十进制数12135,由于百位上的数是'1',故由百位前面的“高位”和百位后面的“低位”共同决定 + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) + 35 + 1个(12100~12135) * 对于十进制数12512,由于百位上的数是'5',故由百位前面的“高位”决定 - + (12 + 1) * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199,12100~12199) + + (12 + 1) * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199,12100~12199) 由此可以看出统计规则主要是在统计第x位时,获得x的“高位”和低位,并根据x与1的关系分类计算,代码如下。 ```cpp From db6354d265de8e72f80dc3f3694d4468ef2de81a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 25 Feb 2014 09:27:50 +0800 Subject: [PATCH 120/327] repair links error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9db5e91..1a40254 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ AlgorithmNote是一个按照主题分类的用于记录、整理和分享算法 Chapters ------------ -0.[Tricky Problems](0.Tricky Problems) +0.[Tricky Problems](0.Tricky Problems.md) 1.[Permutations and Combinations](1.Permutations and Combinations$keywords Permutation, Combination.md)$keywords Permutation, Combination 2.[String dp and array dp](2.String dp and Array dp$keywords dp.md)$keywords dp 3.[Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)$keywords Vector Sum, Tree Sum, Other Sum From e462203e8c910811c93f8c382c03d4257cd80381 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 25 Feb 2014 10:07:36 +0800 Subject: [PATCH 121/327] add EX --- 0.Tricky Problems.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 19f0aa8..8d90f2d 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -1,2 +1,46 @@ ##Tricky Problems 本章用于收录一些微妙、技巧性较强的问题。一般的,问题所属分类模糊或同类问题较少会导致该问题被收录在Tricky Problems,在条件成熟的情况下可以被移出至新的章节。 + +Ex1:[N-Queens II](http://oj.leetcode.com/problems/n-queens-ii/) + +八皇后是递归和回溯的经典问题,递归解法思路比较简明:每次递归选择处在新一行、未被使用列的点,且保证该点与已选择的点斜率绝对值不为1,使用一个Vector来记录已选择的棋子所在列即可。这种做法是有效且正确的,这里介绍求N-queens可行解个数最快的算法。代码如下,思路见注释: +```cpp +class Solution { +public: + int result, upperLim; + int totalNQueens(int n) { + if(n <= 0) return 0; + result = 0; + upperLim = (1 << n) - 1;//掩码,用于过滤掉高于n位的无用bits + recursion(0, 0, 0);//递归初始条件(0x00000000,0x00000000,0x00000000) + return result; + } + + int recursion(int colInfo, int leftDiagonal, int rightDiagonal){ + //3个参数均表示禁位,即之前所选节点对于本次递归所在行选择的限制,来自3方面 + //colInfo表示列禁位,leftDiagonal表示左斜线禁位,rightDiagonal表示右斜线禁位 + //如colInfo == 0x00000003表示最后两列已被选择,不可再次选择 + //leftDiagonal == 0x00000001表示前面选择的点使得本次递归所在行不能选择最后一列 + int pos, p; + //pos表示本次递归所在行可用位置,如0x00000003表示最右两列可用 + //p表示从pos中取出的、只包含“最靠右”的1的数 + if(colInfo == upperLim){ + result++;//所有列已被选择,产生一个可行解 + }else{ + pos = upperLim & ~(colInfo | leftDiagonal | rightDiagonal); + //三个输入参数的或操作是对列、左斜线和右斜线禁位效果合成,取反则是得到可用位 + //与掩码操作过滤掉高于n位的无用bits + while(pos){//不为0表示还有可用位置 + p = pos & -pos;//取出“最靠右”1操作 + pos = pos - p;//消除已选的1 + recursion(colInfo | p, (leftDiagonal | p) << 1, (rightDiagonal | p) >> 1); + //对p的或操作表示该位已选择,对下一层递归起到禁位效果 + //位移的起到表示斜线禁位的效果,举例如下 + //位移前:leftDiagonal == 0001000(7bits), rightDiagonal == 0001000(7bits) + //位移后:leftDiagonal == 0010000(7bits), rightDiagonal == 0000100(7bits) + //显然本次选中第四列会对下一层递归起到第3和第5列禁位效果 + } + } + } +}; +``` From 9f468b6db22465d0c6aa8f1f655399cf301cb401 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 25 Feb 2014 10:09:06 +0800 Subject: [PATCH 122/327] add Ex1 --- 0.Tricky Problems.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 8d90f2d..c5c7350 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -3,7 +3,8 @@ Ex1:[N-Queens II](http://oj.leetcode.com/problems/n-queens-ii/) -八皇后是递归和回溯的经典问题,递归解法思路比较简明:每次递归选择处在新一行、未被使用列的点,且保证该点与已选择的点斜率绝对值不为1,使用一个Vector来记录已选择的棋子所在列即可。这种做法是有效且正确的,这里介绍求N-queens可行解个数最快的算法。代码如下,思路见注释: +八皇后是递归和回溯的经典问题,递归解法思路比较简明:每次递归选择处在新一行、未被使用列的点,且保证该点与已选择的点斜率绝对值不为1,使用一个Vector来记录已选择的棋子所在列即可,这种做法是有效且正确的。 +这里介绍求N-queens可行解个数最快的算法。代码如下,思路见注释: ```cpp class Solution { public: From 954e8e1ab21fef0088d934c31ebca71bbc4dd8a9 Mon Sep 17 00:00:00 2001 From: popolou Date: Wed, 26 Feb 2014 19:56:20 +0800 Subject: [PATCH 123/327] update ex2 --- ...tions$keywords Permutation, Combination.md | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md index ec0e304..0b49736 100644 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ b/1.Permutations and Combinations$keywords Permutation, Combination.md @@ -101,6 +101,35 @@ public: } }; ``` + +Note by[@popolou](https://github.com/popolou): +上面方法时间复杂度稍大,这里提供一种O(n)时间复杂度的算法。 +```cpp +string getPermutation(int n, int k) { + int o[n+1]; + o[0]=1; + for(int i=1;i<=n;i++) + o[i]=o[i-1]*i; + vector v; + string s = ""; + if(k>o[n]) + return s; + for(int i=1;i<=n;i++) + v.push_back(i); + while(n>0){ + int cnt = (k-1)/o[n-1]; + s+=v[cnt]+'0'; + v.erase(v.begin()+cnt); + k=k%o[n-1]; + if(k==0) + k=o[n-1]; + n--; + } + + return s; +} +``` + Ex3:[LeetCode:Permutations](http://oj.leetcode.com/problems/permutations/) 此题要求求出无重复数字的所有的排列,方法可以应用前述的求下一个排列的方法。此处使用递归的方法求解。 From 609d209b9f2742d20bba427f52c3899c4680aa54 Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 1 Mar 2014 12:49:24 +0800 Subject: [PATCH 124/327] update ex7 --- 2.String dp and Array dp$keywords dp.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index fd2bb0b..f5bcfd3 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -373,7 +373,7 @@ public class Solution { int solve2() { int i, j, s; - int[][] dp = new int[N + 1][SUM / 2 + 2]; // 取N+1件物品,总合不超过SUM/2+2,的最大值是多少 + int[][] dp = new int[N + 1][SUM / 2 + 2]; for (i = 1; i <= 2 * N; ++i) { // for (j = 1; j <= Math.min(i, N); ++j) { @@ -385,8 +385,6 @@ public class Solution { } } } - i = N; - int t = SUM / 2 + 1; return dp[N][SUM / 2 + 1]; } From cef8cc2f8cadd0932a3646779f081ba548d6caf1 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 1 Mar 2014 14:33:54 +0800 Subject: [PATCH 125/327] update Ex6 --- 2.String dp and Array dp$keywords dp.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index f5bcfd3..294b7c7 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -314,10 +314,13 @@ public class MyOwn { } ``` -Ex6:最长上升子序列(LIS):给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s12,所以序列长度加一,最后一位为3,3<4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 +=j表示长度为i的递增子序列的最后一个数是j。在对原数组遍历的过程中,每一次都要将a[i]更新到dp的对应位置去。比如a[4]=3,而dp[1]=2,dp[2]=4,表示长度为1的递增子序列最后一个数是2,长度为2的递增子序列最后一个数是4,此时就可以将dp[2]更新为3,因为长度为1的递增子序列最后一位为2,3大于2,所以序列长度加一,最后一位为3,3小于4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 + +Add by[@sc703bupt](https://github.com/sc703bupt): 实际上[@popolou](https://github.com/popolou)的解法是贪心发,使用了一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4 + ```java import java.util.ArrayList; From df87a8eede7ab881276ab5629c76a3ee4088cd3f Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 1 Mar 2014 14:35:46 +0800 Subject: [PATCH 126/327] update Ex6 --- 2.String dp and Array dp$keywords dp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 294b7c7..9b01458 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -319,7 +319,7 @@ Ex6:最长上升子序列(LIS):给出一个序列a1,a2,a3,a4,a5,a6,a7….a 又一个经典的动态规划问题。不同的是这次使用的是一维数组,空间复杂度下降了,dp依旧记录状态,只不过记录的状态很特别,dp[i] =j表示长度为i的递增子序列的最后一个数是j。在对原数组遍历的过程中,每一次都要将a[i]更新到dp的对应位置去。比如a[4]=3,而dp[1]=2,dp[2]=4,表示长度为1的递增子序列最后一个数是2,长度为2的递增子序列最后一个数是4,此时就可以将dp[2]更新为3,因为长度为1的递增子序列最后一位为2,3大于2,所以序列长度加一,最后一位为3,3小于4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 -Add by[@sc703bupt](https://github.com/sc703bupt): 实际上[@popolou](https://github.com/popolou)的解法是贪心发,使用了一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4 +Add by[@sc703bupt](https://github.com/sc703bupt): 实际上[@popolou](https://github.com/popolou)的解法是贪心法,使用了一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素大的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4 ```java import java.util.ArrayList; From 933d4874b7fc0c12855d4cdb40d138da87300b3a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 1 Mar 2014 14:50:38 +0800 Subject: [PATCH 127/327] update Ex6 --- 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index 6174b48..5531357 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -254,9 +254,9 @@ Ex6:[LeetCode:Combination Sum II](http://oj.leetcode.com/problems/combination-su 此题与Ex5区别在于每个数只能用一次,该问题更确切的说是一个01背包问题,使用Set去重,应用以下剪枝方法需要对待选数字升序排序。 -01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k!=M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 +01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k != M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 -**选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk+Σ(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 +**选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 **不选择k**:若t+r-k>=M&&t+(k+1)<=M,一方面判断剩下的物品还足够填满M,同时同选择k情形判断第k+1个物品是否使得X的解可能存在。 From 65cf0768b0f4eca2f672a20c62fccf8a0bbfaf90 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 1 Mar 2014 15:59:06 +0800 Subject: [PATCH 128/327] update Ex8 --- 2.String dp and Array dp$keywords dp.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 9b01458..55e8b65 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -419,6 +419,8 @@ Ex8:求随机数构成的数组中最长的等差数列, 输出等差数列由 这道题的dp[i][j]就更有点神奇了,dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢?j是等差之差,i是最后一个元素。如果能有a[i]-a[t]=j的话,那么dp[t][j]就应该能达到dp[i][j],并且dp[i][j]有可能等于dp[t][j]+1,因为和之前题目中的原因一样,有可能这个状态在之前已经被遍历过了,有更大的值,所以dp[i][j]=max(dp[t][j]+1,dp[i][j])。又,如果dp[i][j]大于我们记录的等差数列长度的最大值,则更新等差数列长度最大值,同时记录等差数列最后一个元素,等差之差。有了这三个元素就可以推出整个等差数列的元素。 +Add by[@sc703bupt](https://github.com/sc703bupt): 等效问题:求解一个数列中需要调整的最少次数使得该数列有序,一次调整操作如将1,2,4,6,5,3变换为1,2,3,4,6,5。 + ```java public class MyOwn { public void solve4(int[] a) { From 0a748f07161116b58be0d0ebea6e27cc8459ca47 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Mar 2014 11:41:42 +0800 Subject: [PATCH 129/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a40254..5f1b320 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ AlgorithmNote ============= Introduction ------------ -AlgorithmNote是一个按照主题分类的用于记录、整理和分享算法思路和解法Github项目,文中涉及的题目来自Leetcode、微软100题、编程之美、OJ、剑指offer及各大算法博客等。 +AlgorithmNote是一个按照主题分类的用于记录、整理和分享算法思路和解法Github项目,旨在分享有趣,具有思维性的算法问题和解答方法。 Chapters ------------ From 97c733eaa51b490b7ab479b4850d2ac504f80c38 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Mar 2014 14:50:42 +0800 Subject: [PATCH 130/327] Create 7.Area Computation$stack.md --- 7.Area Computation$stack.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 7.Area Computation$stack.md diff --git a/7.Area Computation$stack.md b/7.Area Computation$stack.md new file mode 100644 index 0000000..106aadf --- /dev/null +++ b/7.Area Computation$stack.md @@ -0,0 +1 @@ +7.Area Computation$stack From 8b7ae4d655374a31fee660d8601952bc9e8437f3 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Mar 2014 14:52:07 +0800 Subject: [PATCH 131/327] add chapter 7 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f1b320..60fb25c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ Chapters 3.[Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)$keywords Vector Sum, Tree Sum, Other Sum 4.[Search Array](4.Search Array$keywords search.md)$keywords search 5.[Graph](5.Graph&keywords graph.md)$keywords graph -6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search +6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search +7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 0acfb549279a1d8d8769cdfa626c0766d0f3cf07 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Mar 2014 14:52:52 +0800 Subject: [PATCH 132/327] Update and rename 7.Area Computation$stack.md to 7.Area Computation$keyword stack.md --- 7.Area Computation$keyword stack.md | 1 + 7.Area Computation$stack.md | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 7.Area Computation$keyword stack.md delete mode 100644 7.Area Computation$stack.md diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md new file mode 100644 index 0000000..0c536c2 --- /dev/null +++ b/7.Area Computation$keyword stack.md @@ -0,0 +1 @@ +7.Area Computation$keyword stack diff --git a/7.Area Computation$stack.md b/7.Area Computation$stack.md deleted file mode 100644 index 106aadf..0000000 --- a/7.Area Computation$stack.md +++ /dev/null @@ -1 +0,0 @@ -7.Area Computation$stack From 843a89b242164a55e0f035676e2cd4f9891482f8 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sun, 2 Mar 2014 16:52:01 +0800 Subject: [PATCH 133/327] update Ex4 and Ex5 --- 5.Graph&keywords graph.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 38e85c2..4b23ff6 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -172,13 +172,13 @@ public class Solution { for (int i = 1; i <= len; i++) { boolean[] visit = new boolean[len + 1]; for (int j = 1; j <= len; j++) - if (map[i][j]) - if (color[j] != 0) - visit[color[j]] = true; + if (map[i][j])//看j是否是i的邻接节点 + if (color[j] != 0)//如果j被涂色了 + visit[color[j]] = true;//将该颜色做标记 for (int j = 1; j <= len; j++) - if (!visit[j]) { - color[i] = j; - max = Math.max(max, j); + if (!visit[j]) {//从中选出序号最小的未被使用的颜色 + color[i] = j;//涂色 + max = Math.max(max, j);//目前用的颜色数量的最大值 break; } } @@ -197,7 +197,9 @@ public class Solution { Ex5:[Leetcode:Palindrome Partitioning II](http://oj.leetcode.com/problems/palindrome-partitioning-ii/) -此题中先用到了dp标记(详见String dp and array dp),然后用Dijkstra算法计算从0到末尾的最短距离 +此题中先用到了dp标记(详见[2.String dp and Array dp](2.String dp and Array dp$keywords dp.md )),然后用Dijkstra算法计算从0到末尾的最短距离。 + +Added by [@sc703bupt](https://github.com/sc703bupt):这道题的理解是将从0到i的切分次数看成图中的路径距离,对于刚刚加入确定集合的节点i,其对剩余未加入确定集合的节点j的松弛操作为data[j] = min{data[j], data[i]+1},前提是isPalindrome[i][j]为true。 ```java public class Solution { public int minCut(String s) { From d71247776747b559f127e6a4ad6113aee6ca085b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 08:51:08 +0800 Subject: [PATCH 134/327] move addings from Ex8 to Ex6 --- 2.String dp and Array dp$keywords dp.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 55e8b65..8534558 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -321,6 +321,8 @@ Ex6:最长上升子序列(LIS):给出一个序列a1,a2,a3,a4,a5,a6,a7….a Add by[@sc703bupt](https://github.com/sc703bupt): 实际上[@popolou](https://github.com/popolou)的解法是贪心法,使用了一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素大的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4 +Add by[@sc703bupt](https://github.com/sc703bupt): 等效问题:求解一个数列中需要调整的最少次数使得该数列有序,一次调整操作如将1,2,4,6,5,3变换为1,2,3,4,6,5。 + ```java import java.util.ArrayList; @@ -419,8 +421,6 @@ Ex8:求随机数构成的数组中最长的等差数列, 输出等差数列由 这道题的dp[i][j]就更有点神奇了,dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢?j是等差之差,i是最后一个元素。如果能有a[i]-a[t]=j的话,那么dp[t][j]就应该能达到dp[i][j],并且dp[i][j]有可能等于dp[t][j]+1,因为和之前题目中的原因一样,有可能这个状态在之前已经被遍历过了,有更大的值,所以dp[i][j]=max(dp[t][j]+1,dp[i][j])。又,如果dp[i][j]大于我们记录的等差数列长度的最大值,则更新等差数列长度最大值,同时记录等差数列最后一个元素,等差之差。有了这三个元素就可以推出整个等差数列的元素。 -Add by[@sc703bupt](https://github.com/sc703bupt): 等效问题:求解一个数列中需要调整的最少次数使得该数列有序,一次调整操作如将1,2,4,6,5,3变换为1,2,3,4,6,5。 - ```java public class MyOwn { public void solve4(int[] a) { From d8c97e2d92bcd7e5a295c9636f8f959bd5f4a3a6 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 09:00:38 +0800 Subject: [PATCH 135/327] update Ex12 --- 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index 5531357..8962044 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -512,13 +512,13 @@ public: Ex12: Maximum SubMatrix 求解一个二维数组A[N][M]拥有最大和值的子数组。如 -1 -1 -1 --1 5 7 --1 6 8 -结果子数组为 -5 7 -6 8 -和值为26 +1 -1 -1 +-1 5 7 +-1 6 8 +结果子数组为 +5 7 +6 8 +和值为26 考虑将二维数组降维为一维处理,可以获得O(N2M)的时间复杂度。具体做法是使用s,e作为上下界确定矩形的高,将s和e之间的**一列元素的和**等同于一维问题的一个元素。对于特定的s和e,应用一维的O(n)算法求出特定s和e情形下的最大值;穷举s和e的组合,求出全局的最大值。使用dp的方法事先求解列和,dp[i][j]表示第j列中第0个至第i个的和值。 From fd3c4bb152fc204b12802928d82be21eaa1ed440 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 09:01:44 +0800 Subject: [PATCH 136/327] update Ex12 --- 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md index 8962044..fe8685b 100644 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md @@ -511,7 +511,7 @@ public: Ex12: Maximum SubMatrix -求解一个二维数组A[N][M]拥有最大和值的子数组。如 +求解一个二维数组A[N][M]拥有最大和值的子数组,如 1 -1 -1 -1 5 7 -1 6 8 From 7e2326898d45a0d944fe567785a04aee5383d420 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 10:18:47 +0800 Subject: [PATCH 137/327] finish Ex1 --- 7.Area Computation$keyword stack.md | 35 ++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index 0c536c2..11be092 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -1 +1,34 @@ -7.Area Computation$keyword stack +##7.Area Computation$keywords stack +###*Area Computation +本章会介绍几个计算给定一维/二维矩阵计算面积问题,类似的问题在[3.Sum$keywords Vector Sum, Tree Sum, Other Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)的Other Sum小节也有提到,注意到第三章的问题特点 +1、数值可能为负,也即可能出现部分和为负的情况,此时可以很容易舍弃掉这个部分和,因其对后面的部分和没有贡献; +2、矩阵中的元素参与运算时并未受到临近元素的条件约束。 +本章提到的问题元素受临近元素的约束,适合用贪心/动态规划求解。开始了。 + +Ex1:[LeetCode:Container With Most Water](http://oj.leetcode.com/problems/container-with-most-water/) + +题意可理解为:给定一个数组,从中选出两个数字,从而使得以两个数字下标之差为宽,以两个数字较小者为高的矩形面积最大。使用两指针贪心法,总是移动数字较小的指针,贪心策略如下: +* 矩形面积受制于两下标之差,但这个差在两指针靠拢过程中总是缩小的,只能考虑高 +* 高是由较小者决定的,如果移动数字较大的,只能使面积变小(因为宽也变小了),而移动较小的则有可能变大 + +```cpp +class Solution { +public: + int maxArea(vector &height) { + if(height.size() == 0 || height.size() == 1) return 0; + int max = 0, S; + int low = 0, high = height.size()-1; + while(lowmax) max = S; + } + return max; + } +}; +``` From 1bf3131aad57c18720f8050dd068d91426bbc661 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 10:46:31 +0800 Subject: [PATCH 138/327] finish Ex2 --- 7.Area Computation$keyword stack.md | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index 11be092..348f9b1 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -32,3 +32,41 @@ public: } }; ``` + +Ex2:[LeetCode:Trapping Rain Water](http://oj.leetcode.com/problems/trapping-rain-water/) + +这道题如果从两指针的角度来看会变得非常复杂,要考虑每个区间内的柱高情况。换一个角度,只考虑每个柱子上方的容水量C[i] +* `C[i] = Min{LeftHighest[i],RightHighest[i]} - A[i]` + +其中,LeftHighest[i]是柱子i左侧的最高柱高度(不包括自身),RightHighest[i]是柱子i右侧的最高柱高度(不包括自身),A[i]是柱子i的高度。LeftHighest和RightHighest可以用dp求解,最后对C[i]求和即可得到结果。 + +```cpp +class Solution { +public: + int trap(int A[], int n) { + if(n<=2) return 0; + int units = 0; + vector leftHighest; + leftHighest.resize(n); + leftHighest[0] = 0; + for(int i = 1; i<=n-1; i++){ + if(A[i-1] < leftHighest[i-1]){ + leftHighest[i] = leftHighest[i-1]; + }else{ + leftHighest[i] = A[i-1]; + } + } + + int rightHighest = 0, tempUnit = 0; + for(int j = n-2; j>=1; j--){ + if(A[j+1]>rightHighest){ + rightHighest = A[j+1]; + } + tempUnit = min(leftHighest[j],rightHighest)-A[j]; + if(tempUnit <= 0) continue; + units += tempUnit; + } + return units; + } +}; +``` From 5ead90919fced00debd9f77bc83856650242dfd4 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 14:20:01 +0800 Subject: [PATCH 139/327] finish Ex3 --- 7.Area Computation$keyword stack.md | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index 348f9b1..8ae9a56 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -70,3 +70,47 @@ public: } }; ``` + +Ex3:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/largest-rectangle-in-histogram/) + +此题如果用暴力求解同样十分繁琐,以下为O(n)解法,注意到 +* 以小矩形A[i]为高的矩形在整个直方图取到的最大面积取决于A[i]右侧的第一个比A[i]小的小矩形A[j]与A[i]形成的宽度 +* 如果小矩形A[i]右侧没有比A[i]小的小矩形,而左侧有,则宽度为A[i]到直方图的最右端 +* 如果小矩形A[i]右侧没有比A[i]小的小矩形,且左侧也没有(即全局最小),则宽度为直方图的宽度 +这里非常巧妙的运用了stack作为数据结构,用stack维护了以最大递增序列,一旦遇到比栈顶小的小矩形高度则开始计算面积。类似的应用将在Ex4中提及。 + +```cpp + int largestRectangleArea(vector &height) { + if(height.empty()) return 0; + stack stk; + int i = 0, max = 0, temp = 0; + while(i<=height.size()-1){ + if(stk.empty()||height[i]>height[stk.top()]){ + stk.push(i); + i++; + }else{ + int low = stk.top(); + stk.pop(); + if(stk.empty()){ + temp = i * height[low]; + }else{ + temp = (i - stk.top() - 1) * height[low]; + } + max = max > temp?max:temp; + } + } + while(!stk.empty()){ + int low = stk.top(); + stk.pop(); + if(stk.empty()){ + temp = height.size() * height[low]; + }else{ + temp = (height.size() - stk.top() -1) * height[low]; + } + max = max > temp?max:temp; + } + + return max; + } +}; +``` From f3b3a019d1d2a00737ce3115139c5f55afa90694 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 15:16:17 +0800 Subject: [PATCH 140/327] finish Ex3 --- 7.Area Computation$keyword stack.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index 8ae9a56..673936b 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -75,10 +75,20 @@ Ex3:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/la 此题如果用暴力求解同样十分繁琐,以下为O(n)解法,注意到 * 以小矩形A[i]为高的矩形在整个直方图取到的最大面积取决于A[i]右侧的第一个比A[i]小的小矩形A[j]与A[i]形成的宽度 -* 如果小矩形A[i]右侧没有比A[i]小的小矩形,而左侧有,则宽度为A[i]到直方图的最右端 +* 如果小矩形A[i]左侧没有比A[i]小的小矩形,则宽度为0到A[j] * 如果小矩形A[i]右侧没有比A[i]小的小矩形,且左侧也没有(即全局最小),则宽度为直方图的宽度 + 这里非常巧妙的运用了stack作为数据结构,用stack维护了以最大递增序列,一旦遇到比栈顶小的小矩形高度则开始计算面积。类似的应用将在Ex4中提及。 +**注意**:计算面积时不要使用~~temp = (i - low) * height[low]~~,因为(i - low)并不是以height[low]为高的。举个栗子: +对于序列1,3,5,4,2的进出栈和运算过程如下: +* 1,3,5顺序入栈 +* 4使得5出栈计算面积 temp = (3 - 1 - 1) * 5 = 5 (~~使用错误方式计算为temp = (3 - 2) * 5 = 5,一致~~) +* 4入栈 +* 2使得4出栈计算面积 temp = (4 - 1 - 1) * 4 = 8 (~~使用错误方式计算为temp = (4 - 3) * 4 = 4,不一致~~) +* ... +显然错误的计算方式会使得计算过程漏掉中间已被出栈的元素形成的宽度,须知这些已出栈的元素高度肯定大于当前元素,是可以与当前元素形成矩形的。 + ```cpp int largestRectangleArea(vector &height) { if(height.empty()) return 0; @@ -114,3 +124,5 @@ Ex3:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/la } }; ``` + +Ex4:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/largest-rectangle-in-histogram/) From 472ca6ff882776c0d2f767513668c1d1503be398 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 16:11:00 +0800 Subject: [PATCH 141/327] finish Ex4 --- 7.Area Computation$keyword stack.md | 73 +++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index 673936b..d3ee85f 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -95,13 +95,13 @@ Ex3:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/la stack stk; int i = 0, max = 0, temp = 0; while(i<=height.size()-1){ - if(stk.empty()||height[i]>height[stk.top()]){ + if(stk.empty()||height[i]>height[stk.top()]){//如果递增或者是第一个,入栈 stk.push(i); i++; }else{ - int low = stk.top(); + int low = stk.top();//出栈 stk.pop(); - if(stk.empty()){ + if(stk.empty()){//栈为空说明low的左边都大于height[i],同时low到i也是大于height[i]的 temp = i * height[low]; }else{ temp = (i - stk.top() - 1) * height[low]; @@ -125,4 +125,69 @@ Ex3:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/la }; ``` -Ex4:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/largest-rectangle-in-histogram/) +Ex4:[Maximal Rectangle](http://oj.leetcode.com/problems/maximal-rectangle/) + +这道题有几种解法,但较为巧妙并高效的解法是将其降维至1维,并应用Ex3的算法解决。 +降维举例: +1 1 1 +1 0 1 +0 1 1 +分别以第1行,第1、2行和第1、2、3行为目标,得到 +1 1 1 -> 1 1 1 -> 应用Ex3算法 + +1 1 1 +1 0 1 -> 2 0 2 -> 应用Ex3算法 + +1 1 1 +1 0 1 +0 1 1 -> 0 0 3 -> 应用Ex3算法 +故最大面积为3。 +```cpp +class Solution { +public: + int maximalRectangle(vector > &matrix) { + if(matrix.empty()) return 0; + if(matrix[0].empty()) return 0; + vector temp(matrix[0].size(), 0);//record histogram value + stack stk; + int curIndex = 0, maxArea = 0; + for(int i = 0; i <= matrix.size()-1; i++){ + for(int k = 0; k <= matrix[0].size()-1; k++){ + if(matrix[i][k] == '1'){ + temp[k] += 1; + }else{ + temp[k] = 0; + } + } + for(int j = 0; j <= matrix[0].size()-1;){ + if(stk.empty()|| temp[j]>temp[stk.top()]){ + stk.push(j); + j++; + }else{ + curIndex = stk.top(); + stk.pop(); + int tempArea = 0; + if(!stk.empty()){ + tempArea = (j-stk.top()-1)*temp[curIndex]; + }else{ + tempArea = j*temp[curIndex]; + } + maxArea = maxArea>tempArea?maxArea:tempArea; + } + } + while(!stk.empty()){ + curIndex = stk.top(); + stk.pop(); + int tempArea = 0; + if(!stk.empty()){ + tempArea = (temp.size()-stk.top()-1)*temp[curIndex]; + }else{ + tempArea = temp.size()*temp[curIndex]; + } + maxArea = maxArea>tempArea?maxArea:tempArea; + } + } + return maxArea; + } +}; +``` From 01331c19378af7b9c3a3f0049e5cb564ce8a897c Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 16:13:41 +0800 Subject: [PATCH 142/327] update Ex4 --- 7.Area Computation$keyword stack.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index d3ee85f..dd43a59 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -87,6 +87,7 @@ Ex3:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/la * 4入栈 * 2使得4出栈计算面积 temp = (4 - 1 - 1) * 4 = 8 (~~使用错误方式计算为temp = (4 - 3) * 4 = 4,不一致~~) * ... + 显然错误的计算方式会使得计算过程漏掉中间已被出栈的元素形成的宽度,须知这些已出栈的元素高度肯定大于当前元素,是可以与当前元素形成矩形的。 ```cpp @@ -133,14 +134,14 @@ Ex4:[Maximal Rectangle](http://oj.leetcode.com/problems/maximal-rectangle/) 1 0 1 0 1 1 分别以第1行,第1、2行和第1、2、3行为目标,得到 -1 1 1 -> 1 1 1 -> 应用Ex3算法 +1 1 1 -> 1 1 1 -> 应用Ex3算法 1 1 1 -1 0 1 -> 2 0 2 -> 应用Ex3算法 +1 0 1 -> 2 0 2 -> 应用Ex3算法 -1 1 1 -1 0 1 -0 1 1 -> 0 0 3 -> 应用Ex3算法 +1 1 1 +1 0 1 +0 1 1 -> 0 0 3 -> 应用Ex3算法 故最大面积为3。 ```cpp class Solution { From ea1bafaf0821507962b8c615a88f312fe94d86f9 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 16:34:23 +0800 Subject: [PATCH 143/327] finish Ex5 --- 6.Tree&keywords tree, transform, visit.md | 63 ++++++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md index 9da65ef..5e54585 100644 --- a/6.Tree&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -119,11 +119,11 @@ public class Solution { Ex3:树中两个结点的最低公共祖先:给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。 这道题有一个简单的方法。使用的是后序遍历方法,返回最低公共祖先。每当遍历到一个节点时,有以下几种情况: -* 当前节点等于任一个给定节点。返回当前节点。 -* 若不是,若遍历完左节点返回null,说明最低公共祖先在右边 -* 若右节点返回null,说明最低公共祖先在左边 -* 若都不为null,说明当前节点为最低公共祖先 - +* 当前节点等于任一个给定节点。返回当前节点。 +* 若不是,若遍历完左节点返回null,说明最低公共祖先在右边 +* 若右节点返回null,说明最低公共祖先在左边 +* 若都不为null,说明当前节点为最低公共祖先 + ```cpp TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { if (root == NULL) @@ -144,8 +144,9 @@ TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { Ex4:[Leetcode:Recover Binary Search Tree](http://oj.leetcode.com/problems/recover-binary-search-tree/) 本题采用中序遍历。对于二叉排序树来说,中序遍历序列应该是单调递增的。 -* 若被交换的两个元素在原本中序序列中相邻,那么对当前的树中序遍历只会出现一次异常,即后面的数小于前面的数,那将这两个数交换即可 -* 若不相邻,则会出现两次异常。这种情况下我们要记录第一次异常中的首和第二次异常中的尾,将两个数交换。 +* 若被交换的两个元素在原本中序序列中相邻,那么对当前的树中序遍历只会出现一次异常,即后面的数小于前面的数,那将这两个数交换即可 +* 若不相邻,则会出现两次异常。这种情况下我们要记录第一次异常中的首和第二次异常中的尾,将两个数交换。 + ```java public class Solution { TreeNode pre; @@ -177,3 +178,51 @@ public class Solution { } } ``` + +Ex5:[Leetcode:Flatten Binary Tree to Linked List ](http://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/) + +很明显需要采用先序遍历,使用一个指针记录上一个访问的节点,操作步骤为 +* 首先将自身与上一个访问的节点相连,如果存在上一个访问节点的话 +* 将上一个访问节点置为自身,为访问左右孩子做准备 +* 保存右子的指针,因为需要将左子置为右子 +* 对左子进行递归 +* 将左子置空 +* 对右子进行递归 + +```cpp +/** + * Definition for binary tree + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode * preVisit; + void flatten(TreeNode *root) { + preVisit = NULL; + recursive(root); + return; + } + + void recursive(TreeNode * root){ + if(root == NULL) return; + if(preVisit != NULL){ + preVisit->right = root;//1.首先将自身与上一个访问的节点相连,如果存在上一个访问节点的话 + } + preVisit = root;//2.将上一个访问节点置为自身,为访问左右孩子做准备 + TreeNode * right = root->right;//3.保存右子的指针,因为需要将左子置为右子 + if(root->left != NULL){ + recursive(root->left);//4.对左子进行递归 + root->left = NULL;//5.将左子置空 + } + if(right != NULL){ + recursive(right);//6.对右子进行递归 + } + return; + } +}; +``` From bdfe9cbd7acd77df52259912aee2f65f7bf64c74 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 17:07:39 +0800 Subject: [PATCH 144/327] finish Ex6 --- 6.Tree&keywords tree, transform, visit.md | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md index 5e54585..53a1e27 100644 --- a/6.Tree&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -226,3 +226,42 @@ public: } }; ``` + +Ex6:[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal ](http://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) + +类似的问题还有利用前序和中序来还原树,都是先确定根的位置并生成根节点,再寻找左右孩子的区间,递归,并将递归返回的左右孩子赋值给根节点即可。 + +```cpp +class Solution { +public: + TreeNode *buildTree(vector &inorder, vector &postorder) { + if(inorder.size() == 0 || postorder.size() == 0) return NULL; + + return build(inorder, postorder, 0, inorder.size()-1, 0, postorder.size()-1); + } + + TreeNode *build(vector &inorder,vector &postorder, int inBegin, int inEnd, int postBegin, int postEnd){ + if(inBegin > inEnd) return NULL; + + TreeNode * root = new TreeNode(postorder[postEnd]); + TreeNode * left = NULL, * right = NULL; + int index = 0; + + for(int i = inBegin; i <= inEnd; i++){ + if(inorder[i] == postorder[postEnd]){ + index = i; + } + } + + int len = index - inBegin; + + left = build(inorder, postorder, inBegin, index-1, postBegin, postBegin+len-1); + right = build(inorder, postorder, index+1, inEnd, postBegin+len, postEnd-1); + + root->left = left; + root->right = right; + + return root; + } +}; +``` From 239cf8405ce7c6c0ec6ebb06aa5b11200d3f2fad Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 3 Mar 2014 17:11:28 +0800 Subject: [PATCH 145/327] update Ex2 --- 6.Tree&keywords tree, transform, visit.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md index 53a1e27..0a65f3c 100644 --- a/6.Tree&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -70,7 +70,9 @@ int main(){ Ex2:[Leetcode:Binary Tree Zigzag Level Order Traversal](http://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) -首先,既然是层次遍历,肯定需要用到队列。在对每一层进行访问的时候,首先记录队列中的第一个节点和最后一个节点,这是上一层的首尾节点,然后按不同的方向访问每个节点的左右子节点,访问后将该节点弹出队列,这样就能保证加入队列的节点也是有序的。对一层的访问结束后,将方向反转。 +首先,既然是层次遍历,肯定需要用到队列。在对每一层进行访问的时候,首先记录队列中的第一个节点和最后一个节点,这是上一层的首尾节点,然后按不同的方向访问每个节点的左右子节点,访问后将该节点弹出队列,这样就能保证加入队列的节点也是有序的。对一层的访问结束后,将方向反转。 + +Added by [@sc703bupt](https://github.com/sc703bupt):对于层序遍历来说需要分层处理的情况,一种是使用两个指针指向队列中的同一层的头和尾,另一种办法是使用两个队列,两个队列角色在一方为空后调换。 ```java import java.util.ArrayList; import java.util.LinkedList; From a0217d87a798044c9cd58351f21e1ccaf3e647cf Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:16:22 +0800 Subject: [PATCH 146/327] update ex7 --- 4.Search Array$keywords search.md | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 9998fc0..0b35c5b 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -335,3 +335,36 @@ public class MyOwn { } } ``` + +Ex8:[leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) +每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代 +```java +class Solution { +public: + + double findMedianSortedArrays(int A[], int m, int B[], int n) { + int total = m + n; + if (total & 0x1) + return find_kth(A, m, B, n, total / 2 + 1); + else + return (find_kth(A, m, B, n, total / 2) + + find_kth(A, m, B, n, total / 2 + 1)) / 2; + } +private: + + static double find_kth(int A[], int m, int B[], int n, int k) { + //always assume that m is equal or smaller than n + if (m > n) return find_kth(B, n, A, m, k); + if (m == 0) return B[k - 1]; + if (k == 1) return min(A[0], B[0]); + //divide k into two parts + int pa = min(k / 2, m), pb = k - pa; + if (A[pa - 1] < B[pb - 1]) + return find_kth(A + pa, m - pa, B, n, k - pa); + else if (A[pa - 1] > B[pb - 1]) + return find_kth(A, m, B + pb, n - pb, k - pb); + else + return A[pa - 1]; + } +}; +``` From 319fe6ceee6c052940ef88defe10aeadf38a1758 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:22:55 +0800 Subject: [PATCH 147/327] update ex2 --- 0.Tricky Problems.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index c5c7350..92fe39f 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -45,3 +45,19 @@ public: } }; ``` +Ex2:[leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/) +二进制转格雷码:gray = (binary) xor (binary >> 1) +```cpp +class Solution { +public: + + vector grayCode(int n) { + vector vec; + int size = 1 << n; + for (int i = 0; i < size; i++) { + vec.push_back(i^(i >> 1)); + } + return vec; + } +}; +``` From f91eee502376865cd29b5712045edc8b65ab3183 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:28:18 +0800 Subject: [PATCH 148/327] named --- Overwrite$keywords overwrite.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Overwrite$keywords overwrite.md diff --git a/Overwrite$keywords overwrite.md b/Overwrite$keywords overwrite.md new file mode 100644 index 0000000..c003413 --- /dev/null +++ b/Overwrite$keywords overwrite.md @@ -0,0 +1 @@ +###Overwrite$keywords overwrite From f2afe7584c7486df08087c6f7a0f3d0b308c4a9c Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:28:34 +0800 Subject: [PATCH 149/327] Rename Overwrite$keywords overwrite.md to 8.Overwrite$keywords overwrite.md --- ...ite$keywords overwrite.md => 8.Overwrite$keywords overwrite.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Overwrite$keywords overwrite.md => 8.Overwrite$keywords overwrite.md (100%) diff --git a/Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md similarity index 100% rename from Overwrite$keywords overwrite.md rename to 8.Overwrite$keywords overwrite.md From 44993a08f1781f1c7ff09d2e5c065a18a5d914d1 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:36:44 +0800 Subject: [PATCH 150/327] Update Ex1 --- 8.Overwrite$keywords overwrite.md | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index c003413..b4a2abc 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -1 +1,33 @@ ###Overwrite$keywords overwrite +Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) +```cpp +class Solution { +public: + + char *strStr(char *haystack, char *needle) { + int len1 = strlen(haystack); + int len2 = strlen(needle); + if (len1 < len2) + return NULL; + if (len2 == 0) + return haystack; + char* p2 = haystack; + for (int i = 0; i < len1 - len2 + 1; i++) { + char* p1 = needle; + char* p_old = (char*) p2; + while (*p1 && *p2) { + if (*p1 == *p2) { + p1++; + p2++; + } else + break; + } + if (!*p1) + return p_old; + p2 = p_old + 1; + } + return NULL; + } +}; +``` + From 52893f3f3569dc1e85713fe0c21ec79b12068fd0 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:39:53 +0800 Subject: [PATCH 151/327] update ex2 --- 8.Overwrite$keywords overwrite.md | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index b4a2abc..2f7074e 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -3,7 +3,6 @@ Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) ```cpp class Solution { public: - char *strStr(char *haystack, char *needle) { int len1 = strlen(haystack); int len2 = strlen(needle); @@ -31,3 +30,38 @@ public: }; ``` +Ex2:[String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) +主要判断溢出问题 +```cpp +class Solution { +public: + + int atoi(const char *str) { + int i = 0; + int len = strlen(str); + bool positive = true; + while (str[i] == ' ' && i < len) + i++; + if (str[i] == '+') + i++; + else if (str[i] == '-') { + positive = false; + i++; + } + long long sum = 0; + for (; i < len; i++) { + if (str[i] < '0' || str[i] > '9') + break; + sum = sum * 10 + str[i] - '0'; + } + sum = positive == true ? sum : -1 * sum; + int min = 0x80000000; + int max = 0x7fffffff; + if (sum < min) + return 0x80000000; + else if (sum > max) + return 0x7fffffff; + return (int) sum; + } +}; +``` From 19f193f3d9db46da80f463e02fabdb7864d38dbb Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:40:53 +0800 Subject: [PATCH 152/327] Update 8.Overwrite$keywords overwrite.md --- 8.Overwrite$keywords overwrite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 2f7074e..5667683 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -30,7 +30,7 @@ public: }; ``` -Ex2:[String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) +Ex2:[String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) 主要判断溢出问题 ```cpp class Solution { From 08cdfb8f4fd37932fe13829dbabdbd8e46747ee7 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:41:23 +0800 Subject: [PATCH 153/327] Update 8.Overwrite$keywords overwrite.md --- 8.Overwrite$keywords overwrite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 5667683..2f7074e 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -30,7 +30,7 @@ public: }; ``` -Ex2:[String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) +Ex2:[String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) 主要判断溢出问题 ```cpp class Solution { From 1e8cc17ecaef07845b9204ab006946bd0480073c Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:41:57 +0800 Subject: [PATCH 154/327] Update 8.Overwrite$keywords overwrite.md --- 8.Overwrite$keywords overwrite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 2f7074e..041dda5 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -30,7 +30,7 @@ public: }; ``` -Ex2:[String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) +Ex2:[Leetcode:String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) 主要判断溢出问题 ```cpp class Solution { From 52998f0fd6213b89993c342280140df3b7844b70 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:45:07 +0800 Subject: [PATCH 155/327] update ex3 --- 8.Overwrite$keywords overwrite.md | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 041dda5..8c75392 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -65,3 +65,43 @@ public: } }; ``` + +Ex3:[Leetcode:Add Binary](http://oj.leetcode.com/problems/add-binary/) +```cpp +//add Binary + +class Solution { +public: + + string addBinary(string a, string b) { + // Start typing your C/C++ solution below + // DO NOT write int main() function + string c; + int flag = 0; + int lena = a.size(); + int lenb = b.size(); + int len = abs(lena - lenb); + string append(len, '0'); + if (lena > lenb) { + b = append + b; + c.resize(lena, '0'); + } else { + a = append + a; + c.resize(lenb, '0'); + } + for (int j = c.size() - 1; j >= 0; j--) { + int current = (a[j] - '0') ^(b[j] - '0') ^flag; + if ((a[j] - '0') +(b[j] - '0') + flag > 1) + flag = 1; + else + flag = 0; + c[j] = current + '0'; + } + if (flag == 1) + c = '1' + c; + + return c; + + } +}; +``` From 5dae69a6d19a448e7ad248faa393c18957966e4a Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:48:04 +0800 Subject: [PATCH 156/327] Update Ex4 --- 8.Overwrite$keywords overwrite.md | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 8c75392..cec3fa6 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -105,3 +105,63 @@ public: } }; ``` +Ex4[Leetcode:Valid Number](oj.leetcode.com/problems/valid-number/) +复杂的判断条件 +```cpp +class Solution { +public: + + bool isNumber(const char *s) { + if (s == NULL || s[0] == '\0') return false; + bool cansign = true; + bool cane = false; + bool havee = false; + bool candot = true; + bool onlyspace = false; + bool havenum = false; + bool numbegin = false; + while (*s != '\0') { + char c = *(s++); + if (c == ' ') { + if (numbegin) + onlyspace = true; + continue; //skip space + } else if (onlyspace) { + return false; + } + if (c == '+' || c == '-') { + if (!cansign) return false; + cansign = false; + numbegin = true; + continue; + } + if (c == 'e') { + if (!cane) return false; + cane = false; + havenum = false; + numbegin = true; + cansign = true; + havee = true; + candot = false; + continue; + } + if (c == '.') { + if (!candot) return false; + candot = false; + numbegin = true; + cansign = false; + continue; + } + if (c >= '0' && c <= '9') { + havenum = true; + numbegin = true; + cansign = false; + if (!havee) cane = true; + } else { + return false; + } + } + return havenum; + } +}; +``` From 9efeb145b2f46358a2ca9fd622dcee710ff18a9d Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:48:32 +0800 Subject: [PATCH 157/327] Update 8.Overwrite$keywords overwrite.md --- 8.Overwrite$keywords overwrite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index cec3fa6..96ff350 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -105,7 +105,7 @@ public: } }; ``` -Ex4[Leetcode:Valid Number](oj.leetcode.com/problems/valid-number/) +Ex4:[Leetcode:Valid Number](oj.leetcode.com/problems/valid-number/) 复杂的判断条件 ```cpp class Solution { From 97b014310ed1f49fdc23ff11c8d8c3571aaf9745 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:52:25 +0800 Subject: [PATCH 158/327] update ex5 and ex6 --- 8.Overwrite$keywords overwrite.md | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 96ff350..90e9c88 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -165,3 +165,53 @@ public: } }; ``` +Ex5:[Leetcode:Pow(x, n)](http://oj.leetcode.com/problems/powx-n/) +```cpp +class Solution { +public: + double pow(double x, int n) { + // Start typing your C/C++ solution below + // DO NOT write int main() function + if(n == 0) return 1; + else if(n > 0) + { + double half = pow(x, n/2); + if(n%2 == 0) return half*half; + else return half*half*x; + } + else + { + n = -n; + double half = pow(x, n/2); + if(n%2 == 0) return 1.0/(half*half); + else return 1.0/(half*half*x); + } + } +}; +``` + +Ex6:[Leetcode:Sqrt(x)](http://oj.leetcode.com/problems/sqrtx/) +```cpp +class Solution { +public: + + int sqrt(int x) { + int left = 1, right = x / 2; + int mid; + int last_mid; // 记录最近一次mid + if (x < 2) return x; + while (left <= right) { + mid = left + (right - left) / 2; + if (x / mid > mid) { // 不要用x > mid * mid,会溢出 + left = mid + 1; + last_mid = mid; + } else if (x / mid < mid) { + right = mid - 1; + } else { + return mid; + } + } + return last_mid; + } +}; +``` From feba11dfb1646bebf7f1ef4967860fee8f00b000 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 15:57:02 +0800 Subject: [PATCH 159/327] Update Ex7 --- 8.Overwrite$keywords overwrite.md | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 90e9c88..957d28d 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -215,3 +215,38 @@ public: } }; ``` +Ex7:[Leetcode:Multiply Strings](http://oj.leetcode.com/problems/multiply-strings/) +```cpp +class Solution { +public: + string multiply(string num1, string num2) { + int len1 = num1.length(); + int len2 = num2.length(); + vector res(len1+len2); + vector n1; + vector n2; + for(int i=num1.length()-1;i>=0;--i) + n1.push_back(num1[i]-'0'); + for(int i=num2.length()-1;i>=0;--i) + n2.push_back(num2[i]-'0'); + for(int i=0;i=0) + --i; + if(i<0) + return "0"; + while(i>=0){ + ret.push_back('0'+res[i]-0); + --i; + } + return ret; + } +}; +``` From da15803a2985c07e12a2c8d02f97fe7995ee8109 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 16:22:28 +0800 Subject: [PATCH 160/327] update ex9 --- 4.Search Array$keywords search.md | 54 ++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 0b35c5b..1698e1e 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -336,7 +336,7 @@ public class MyOwn { } ``` -Ex8:[leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) +Ex8:[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) 每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代 ```java class Solution { @@ -368,3 +368,55 @@ private: } }; ``` + +Ex9:[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/) +普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。然后根据i更新最右R。 +```cpp +class Solution { +public: + // Transform S into T. + // For example, S = "abba", T = "^#a#b#b#a#$". + // ^ and $ signs are sentinels appended to each end to avoid bounds checking + + string preProcess(string s) { + int n = s.length(); + if (n == 0) return "^$"; + string ret = "^"; + for (int i = 0; i < n; i++) ret += "#" + s.substr(i, 1); + ret += "#$"; + return ret; + } + + string longestPalindrome(string s) { + string T = preProcess(s); + const int n = T.length(); + // 以T[i] 为中心,向左/右扩张的长度,不包含T[i] 自己, + // 因此P[i] 是源字符串中回文串的长度 + int P[n]; + int C = 0, R = 0; + for (int i = 1; i < n - 1; i++) { + int i_mirror = 2 * C - i; // equals to i' = C - (i-C) + P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; + // Attempt to expand palindrome centered at i + while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) + P[i]++; + // If palindrome centered at i expand past R, + // adjust center based on expanded palindrome. + if (i + P[i] > R) { + C = i; + R = i + P[i]; + } + } + // Find the maximum element in P. + int max_len = 0; + int center_index = 0; + for (int i = 1; i < n - 1; i++) { + if (P[i] > max_len) { + max_len = P[i]; + center_index = i; + } + } + return s.substr((center_index - 1 - max_len) / 2, max_len); + } +}; +``` From eb1af6b33bc4c9518db7495bc68725af79207d4c Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 16:24:22 +0800 Subject: [PATCH 161/327] update ex9 --- 4.Search Array$keywords search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 1698e1e..d4774a7 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -370,7 +370,7 @@ private: ``` Ex9:[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/) -普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。然后根据i更新最右R。 +普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。之后长度若能扩展则继续扩展。然后根据i更新最右R。 ```cpp class Solution { public: From 2a35e3f164eab26441f2d5833d0f3269e24801bf Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 16:30:31 +0800 Subject: [PATCH 162/327] update ex3 --- 0.Tricky Problems.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 92fe39f..1b5fbaa 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -61,3 +61,28 @@ public: } }; ``` + +Ex3:[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/) +```cpp +class Solution { +public: + + bool isMatch(const char *s, const char *p) { + if (*p == '\0') return *s == '\0'; + // next char is not '*', then must match current character + if (*(p + 1) != '*') { + if (*p == *s || (*p == '.' && *s != '\0')) + return isMatch(s + 1, p + 1); + else + return false; + } else { // next char is '*' + while (*p == *s || (*p == '.' && *s != '\0')) { + if (isMatch(s, p + 2)) + return true; + s++; + } + return isMatch(s, p + 2); + } + } +}; +``` From fd26d31df5a0318c78f33b37f618c07f247050e7 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 16:33:16 +0800 Subject: [PATCH 163/327] update ex4 --- 0.Tricky Problems.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 1b5fbaa..f675ee0 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -86,3 +86,41 @@ public: } }; ``` + +Ex4:[Leetcode:Simplify Path](http://oj.leetcode.com/problems/simplify-path/) +```cpp +class Solution { +public: + + string simplifyPath(string path) { + // Start typing your C/C++ solution below + // DO NOT write int main() function + vector pathes; + string seg = ""; + for (int i = 0; i <= path.size(); ++i) { + if (i == path.size() || path[i] == '/') { + if (seg == "..") { + if (pathes.size() > 0) { + pathes.pop_back(); + } else { + //return "/";//error, in the test set, this case just ignore + } + } else if (seg == ".") { + //do nothing + } else if (seg.size() > 0) { + pathes.push_back(seg); + } + seg = ""; + } else { + seg += path[i]; + } + } + string ret = "/"; + for (int i = 0; i < pathes.size(); ++i) { + if (i > 0) ret += "/"; + ret += pathes[i]; + } + return ret; + } +}; +``` From ed7d23b91720e7f60229e10c6cf3be6a0c7b70ef Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 16:36:48 +0800 Subject: [PATCH 164/327] named --- 9.Sliding window$keywords window.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 9.Sliding window$keywords window.md diff --git a/9.Sliding window$keywords window.md b/9.Sliding window$keywords window.md new file mode 100644 index 0000000..c0f1169 --- /dev/null +++ b/9.Sliding window$keywords window.md @@ -0,0 +1 @@ +###Sliding window$keywords window From 27a812aba4e42ec03d5fa5307669f93bde55482d Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 16:44:55 +0800 Subject: [PATCH 165/327] Update Ex1 --- 9.Sliding window$keywords window.md | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/9.Sliding window$keywords window.md b/9.Sliding window$keywords window.md index c0f1169..4eced5e 100644 --- a/9.Sliding window$keywords window.md +++ b/9.Sliding window$keywords window.md @@ -1 +1,32 @@ ###Sliding window$keywords window + +Ex1:[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/) +```cpp +class Solution { +public: + + int longestValidParentheses(string s) { + int max_len = 0, last = -1; // the position of the last ')' + stack lefts; // keep track of the positions of non-matching '('s + for (int i = 0; i < s.size(); ++i) { + if (s[i] == '(') { + lefts.push(i); + } else { + if (lefts.empty()) { + // no matching left + last = i; + } else { + // find a matching pair + lefts.pop(); + if (lefts.empty()) { + max_len = max(max_len, i - last); + } else { + max_len = max(max_len, i - lefts.top()); + } + } + } + } + return max_len; + } +}; +``` From b9d81981e172de2862e55e83a657c21859cf0fcb Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 16:54:44 +0800 Subject: [PATCH 166/327] Update ex5 --- 0.Tricky Problems.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index f675ee0..5a5ed8e 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -124,3 +124,46 @@ public: } }; ``` + +Ex5:[Leetcode:Evaluate Reverse Polish Notation](http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/) +```java +public class Solution { + public int evalRPN(String[] tokens) { + + int returnValue = 0; + + String operators = "+-*/"; + + Stack stack = new Stack(); + + for(String t : tokens){ + if(!operators.contains(t)){ + stack.push(t); + }else{ + int a = Integer.valueOf(stack.pop()); + int b = Integer.valueOf(stack.pop()); + int index = operators.indexOf(t); + switch(index){ + case 0: + stack.push(String.valueOf(a+b)); + break; + case 1: + stack.push(String.valueOf(b-a)); + break; + case 2: + stack.push(String.valueOf(a*b)); + break; + case 3: + stack.push(String.valueOf(b/a)); + break; + } + } + } + + returnValue = Integer.valueOf(stack.pop()); + + return returnValue; + + } +} +``` From a5439309ab81ca929cb6e43e3df75602659c00cc Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 21:35:31 +0800 Subject: [PATCH 167/327] update ex2 --- 9.Sliding window$keywords window.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/9.Sliding window$keywords window.md b/9.Sliding window$keywords window.md index 4eced5e..b0e84e1 100644 --- a/9.Sliding window$keywords window.md +++ b/9.Sliding window$keywords window.md @@ -30,3 +30,26 @@ public: } }; ``` +Ex2:[Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/) +```cpp +class Solution { +public: + + int lengthOfLongestSubstring(string s) { + const int ASCII_MAX = 26; + int last[ASCII_MAX]; // 记录字符上次出现过的位置 + fill(last, last + ASCII_MAX, -1); // 0 也是有效位置,因此初始化为-1 + int len = 0, max_len = 0; + for (size_t i = 0; i < s.size(); i++, len++) { + if (last[s[i] - 'a'] >= 0) { + max_len = max(len, max_len); + len = 0; + i = last[s[i] - 'a'] + 1; + fill(last, last + ASCII_MAX, -1); // 重新开始 + } + last[s[i] - 'a'] = i; + } + return max(len, max_len); // 别忘了最后一次,例如"abcd" + } +}; +``` From 5d3851d90fbacb37a9bf000949cbf79b675b6606 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 21:44:14 +0800 Subject: [PATCH 168/327] update ex6 --- 0.Tricky Problems.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 5a5ed8e..aeb5a5c 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -167,3 +167,26 @@ public class Solution { } } ``` +Ex6:[Leetcode:Decode Ways](http://oj.leetcode.com/problems/decode-ways/) +```cpp +class Solution { +public: + + int numDecodings(const string &s) { + if (s.empty() || s[0] == '0') return 0; + int prev = 0; + int cur = 1; + // 长度为n 的字符串,有n+1 个阶梯 + for (size_t i = 1; i <= s.size(); ++i) { + if (s[i - 1] == '0') cur = 0; + if (i < 2 || !(s[i - 2] == '1' || + (s[i - 2] == '2' && s[i - 1] <= '6'))) + prev = 0; + int tmp = cur; + cur = prev + cur; + prev = tmp; + } + return cur; + } +}; +``` From 9df5f099d4b5b172314138d8c5478127dc80f83e Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 21:54:49 +0800 Subject: [PATCH 169/327] update ex9 --- 2.String dp and Array dp$keywords dp.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 8534558..fdaad55 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -464,4 +464,20 @@ public class MyOwn { } ``` +Ex9:[Leetcode:Distinct Subsequences](http://oj.leetcode.com/problems/distinct-subsequences/) +```cpp +class Solution { +public: + int numDistinct(const string &S, const string &T) { + vector f(T.size() + 1); + f[0] = 1; + for (int i = 0; i < S.size(); ++i) { + for (int j = T.size() - 1; j >= 0; --j) { + f[j + 1] += S[i] == T[j] ? f[j] : 0; + } + } + return f[T.size()]; + } +}; +``` From 9e7a6129508c8f75719669b2ba023b5eda7a66e8 Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 22:19:02 +0800 Subject: [PATCH 170/327] Update Ex7 --- 0.Tricky Problems.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index aeb5a5c..45d521e 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -190,3 +190,70 @@ public: } }; ``` + +Ex7:[Leetcode:Text Justification](http://oj.leetcode.com/problems/text-justification/) +```java +public class Solution { + public ArrayList fullJustify(String[] words, int L) { + // Start typing your Java solution below + // DO NOT write main() function + ArrayList result = new ArrayList(); + String[] spaces = new String[L+1]; + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < L+1; i++) { + spaces[i] = builder.toString(); + builder.append(' '); + } + + int len = words.length; + + int i = 0; + while (i < len) { + int j = i; + int total = words[i].length(); + while (true) { + j++; + if (j == len) break; + int w = words[j].length(); + if (total + w + 1 > L) break; + total += w + 1; + } + int left = L - total; + int c = j - i; + if (c == 1) { // single word + StringBuilder sb = new StringBuilder(words[i]); + sb.append(spaces[left]); + result.add(sb.toString()); + } + else { // multi-word + if (j == len) { // last line + StringBuilder sb = new StringBuilder(words[i]); + for (int x = i+1; x < j; x++) { + sb.append(' '); + sb.append(words[x]); + } + sb.append(spaces[left]); + result.add(sb.toString()); + } + else { + int k = left / (c - 1); // extra ' ' for every gap + int l = left - k * (c - 1); // count for first gaps with extra '' + StringBuilder sb = new StringBuilder(words[i]); + for (int x = i+1; x < j; x++) { + if (l > 0) { + sb.append(' '); + l--; + } + sb.append(' '); + sb.append(spaces[k]); + sb.append(words[x]); + } + result.add(sb.toString()); + } + } + i = j; + } + return result; + } +} +``` From 7f7471f497a923979c5e76e9866a283bebbbc25a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 6 Mar 2014 22:34:13 +0800 Subject: [PATCH 171/327] Create 10. Big Data Processing$keywords Bigdata.md --- 10. Big Data Processing$keywords Bigdata.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 10. Big Data Processing$keywords Bigdata.md diff --git a/10. Big Data Processing$keywords Bigdata.md b/10. Big Data Processing$keywords Bigdata.md new file mode 100644 index 0000000..bffe632 --- /dev/null +++ b/10. Big Data Processing$keywords Bigdata.md @@ -0,0 +1 @@ +##Big Data Processing From efc3ed371eeeab38939fcbe2cfa5db0e719e5c94 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 6 Mar 2014 22:36:38 +0800 Subject: [PATCH 172/327] add chapters 8,9,10 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 60fb25c..6bd0603 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Chapters 5.[Graph](5.Graph&keywords graph.md)$keywords graph 6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search 7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack +8.[Overwrite](8.Overwrite$keywords overwrite.md)$keywords overwrite +9.[Sliding window](9.Sliding window$keywords window.md)$keywords window +10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 0ee1d1537418a4698011d607ca9b08fcffb54be6 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 6 Mar 2014 22:37:10 +0800 Subject: [PATCH 173/327] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6bd0603..ca53097 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ Chapters 5.[Graph](5.Graph&keywords graph.md)$keywords graph 6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search 7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack -8.[Overwrite](8.Overwrite$keywords overwrite.md)$keywords overwrite -9.[Sliding window](9.Sliding window$keywords window.md)$keywords window -10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata +8.[Overwrite](8.Overwrite$keywords overwrite.md)$keywords overwrite +9.[Sliding window](9.Sliding window$keywords window.md)$keywords window +10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From bf6a1df84d7c2ad34e0803b6eba4bf6f5306b7b1 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 6 Mar 2014 22:37:32 +0800 Subject: [PATCH 174/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca53097..96fa33c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Chapters 4.[Search Array](4.Search Array$keywords search.md)$keywords search 5.[Graph](5.Graph&keywords graph.md)$keywords graph 6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search -7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack +7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack 8.[Overwrite](8.Overwrite$keywords overwrite.md)$keywords overwrite 9.[Sliding window](9.Sliding window$keywords window.md)$keywords window 10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata From cffba2b6e8820df00088b638afa4193d9fa9086d Mon Sep 17 00:00:00 2001 From: popolou Date: Thu, 6 Mar 2014 22:43:01 +0800 Subject: [PATCH 175/327] Update Ex8 --- 0.Tricky Problems.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 45d521e..9b246b4 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -257,3 +257,40 @@ public class Solution { } } ``` +Ex8:[Leetcode:Max Points on a Line](http://oj.leetcode.com/problems/max-points-on-a-line/) +```cpp +class Solution { +public: + + int maxPoints(vector &points) { + if (points.size() == 0) + return 0; + if (points.size() == 1) + return 1; + int result = 0; + for (int i = 0; i < points.size(); i++) { + for (int j = i + 1; j < points.size(); j++) { + bool flag = false; + int cnt = 0; + int a, b, c, d; + if (points[i].x == points[j].x) + flag = true; + else { + a = points[j].x * points[i].y; + b = points[i].x * points[j].y; + c = points[j].x - points[i].x; + d = points[j].y - points[i].y; + } + for (int k = 0; k < points.size(); k++) { + if (flag && points[k].x == points[i].x) + cnt++; + if (!flag && (a + d * points[k].x == b + c * points[k].y)) + cnt++; + } + result = max(result, cnt); + } + } + return result; + } +}; +``` From cc1b89a420cbd87239c545335a0013ddbdf2e320 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 6 Mar 2014 22:51:15 +0800 Subject: [PATCH 176/327] add Ex1 and --- 10. Big Data Processing$keywords Bigdata.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/10. Big Data Processing$keywords Bigdata.md b/10. Big Data Processing$keywords Bigdata.md index bffe632..9fd32a7 100644 --- a/10. Big Data Processing$keywords Bigdata.md +++ b/10. Big Data Processing$keywords Bigdata.md @@ -1 +1,7 @@ ##Big Data Processing +###*Big Data Processing +大数据处理往往因数据量过大导致数据无法全部加载入内存,又或即便能够加载入内存,处理速度无法保证。此外,大数据问题又被许多因素制约,比如网络传输带宽,内存空间限制,响应时间,因此产生了不少有趣的问题,而这些问题的解决离不开分治思想,内存排序-外存合并以及哈希映射的设计与实现。 + +Ex1.给定1台主机和100台从机,从机只能与主机通信,且通信速率仅有1KB/s。每台从机上有2G个INT型数据,要求在合理的时间范围内求出所有数据的中位数。 + +Ex2.给定100G条IP数据以及一张划分IP域的表,使用最快的方法统计出每个IP域的IP个数。 From 7987557c6d24be67cf2175b8dbfeeb05e72845f1 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 09:01:33 +0800 Subject: [PATCH 177/327] Update 0.Tricky Problems.md --- 0.Tricky Problems.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 9b246b4..7962b37 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -63,6 +63,8 @@ public: ``` Ex3:[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/) +每次首先判断当前字符的下一个字符是不是'*' +**是\\*** ```cpp class Solution { public: From 19d998ad4479a5a8dc771083c59e104ad7f0061c Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 09:21:41 +0800 Subject: [PATCH 178/327] Update Ex3 --- 0.Tricky Problems.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 7962b37..92760bb 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -63,8 +63,9 @@ public: ``` Ex3:[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/) -每次首先判断当前字符的下一个字符是不是'*' -**是\\*** +每次首先判断p当前字符的下一个字符是不是* +* 不是\*,如果s和p的当前字符相同,判断s和p的下一位 +* 是\*,若p的当前字符是'.',则可以匹配到s的末尾;否则,用p的当前字符一直去匹配s,若p当前字符等于s当前字符,判断若p重复0次s和p是否能匹配;若能则跳出循环,若不能,用p当前字符继续匹配s的下一位。当p的当前字符终于和s的当前字符不相等时,则返回p后面的字符串和s是否匹配 ```cpp class Solution { public: From 2d7417e776148070b6658f44ddc7a74e31a16885 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 09:31:11 +0800 Subject: [PATCH 179/327] Update Ex4 --- 0.Tricky Problems.md | 1 + 1 file changed, 1 insertion(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 92760bb..8b2c123 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -91,6 +91,7 @@ public: ``` Ex4:[Leetcode:Simplify Path](http://oj.leetcode.com/problems/simplify-path/) +在每次碰到/之前,都将前面的字符串保存起来;碰到/或者遍历到路径结束,若字符串为'..',表示上一目录;若为'.',表示当前目录;其余情况保存路径,然后重新记录。 ```cpp class Solution { public: From 0b174e009ed0ad61c39e330cba7deeed83283e12 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 7 Mar 2014 09:34:46 +0800 Subject: [PATCH 180/327] finish Ex1 --- 10. Big Data Processing$keywords Bigdata.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/10. Big Data Processing$keywords Bigdata.md b/10. Big Data Processing$keywords Bigdata.md index 9fd32a7..962b0dc 100644 --- a/10. Big Data Processing$keywords Bigdata.md +++ b/10. Big Data Processing$keywords Bigdata.md @@ -2,6 +2,19 @@ ###*Big Data Processing 大数据处理往往因数据量过大导致数据无法全部加载入内存,又或即便能够加载入内存,处理速度无法保证。此外,大数据问题又被许多因素制约,比如网络传输带宽,内存空间限制,响应时间,因此产生了不少有趣的问题,而这些问题的解决离不开分治思想,内存排序-外存合并以及哈希映射的设计与实现。 -Ex1.给定1台主机和100台从机,从机只能与主机通信,且通信速率仅有1KB/s。每台从机上有2G个INT型数据,要求在合理的时间范围内求出所有数据的中位数。 +**Ex1:给定1台主机和100台从机,从机只能与主机通信,且通信速率仅有1KB/s。每台从机上有2G个INT型数据,要求在合理的时间范围内求出所有数据的中位数。** -Ex2.给定100G条IP数据以及一张划分IP域的表,使用最快的方法统计出每个IP域的IP个数。 +此题的思考思路如下。通信速率1KB/s说明通信速率非常低,基本不可能用于传输大量的数据,1s也只能传输256个INT数字,2G的传输不可能在合理时间内完成,通信带宽只能用于传输统计信息,如最大最小值,自身的中位数,平均值等信息。题目要求求出所有数据的中位数。 +考虑中位数的性质,对于一个长度为N的数组,其中位数左侧和右侧各有(N-1/2)个数字,从左侧和右侧分别剔除x个数不会影响原中位数的性质。 +对于题目给出的无序数据,先进行内存排序(如快排),再进行区块划分。假设到INT数据的范围为D,划分的区块长度为L(如0-200,200-400...),则区块数量为D/L。此时统计每个区块的包含数字的个数得到(N1,N2..N(D/L)),向主机发送这个信息并接收其他所有从机的同类信息,可获得如下信息矩阵 +从机1:(N1,N2..N(D/L)) +从机2:(N1,N2..N(D/L)) +. +. +. +从机100:(N1,N2..N(D/L)) +对应列相加后得到(TN1,TN2..TN(D/L)),此时容易知道要求中位数为第Mid = (2G/4)/2 = 256M个,从TN数组的左侧开始做减法,即Mid -= TNk直到Mid小于0,即可知道中位数所在区间。 +如果该区间还是过大,则可递归进行上述过程,再次分块并求Mid' = Mid - ΣTNk,直到求出最后结果。 + + +**Ex2:给定100G条IP数据以及一张划分IP域的表,使用最快的方法统计出每个IP域的IP个数。** From cc77d0d9d36b1e913791acc9569c2dfd381208be Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 09:42:53 +0800 Subject: [PATCH 181/327] Update Ex5 --- 0.Tricky Problems.md | 1 + 1 file changed, 1 insertion(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 8b2c123..c045119 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -130,6 +130,7 @@ public: ``` Ex5:[Leetcode:Evaluate Reverse Polish Notation](http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/) +一个栈保存操作数,当遇到操作符是,弹出两个操作数,计算完后将结果压入栈 ```java public class Solution { public int evalRPN(String[] tokens) { From 5e3902dba8a3b20033ad75a20c0646e144d32585 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 7 Mar 2014 09:46:42 +0800 Subject: [PATCH 182/327] finish Ex2 --- 10. Big Data Processing$keywords Bigdata.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/10. Big Data Processing$keywords Bigdata.md b/10. Big Data Processing$keywords Bigdata.md index 962b0dc..7e504e9 100644 --- a/10. Big Data Processing$keywords Bigdata.md +++ b/10. Big Data Processing$keywords Bigdata.md @@ -18,3 +18,5 @@ **Ex2:给定100G条IP数据以及一张划分IP域的表,使用最快的方法统计出每个IP域的IP个数。** + +IP由32位组成,共4G个,因此100G条IP必然存在重复,考虑使用一个MAP进行压缩,压缩比达到25:1。又因为划分IP域的表的是单调递增的,如果使用一个有序的MAP,则可以在遍历MAP的同时统计出所有结果。 From 8af222b9cff51096f600b9df72d5a42629cd8a77 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 11:26:15 +0800 Subject: [PATCH 183/327] Update Ex6 --- 0.Tricky Problems.md | 1 + 1 file changed, 1 insertion(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index c045119..de2af93 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -173,6 +173,7 @@ public class Solution { } ``` Ex6:[Leetcode:Decode Ways](http://oj.leetcode.com/problems/decode-ways/) +每次遍历时,pre表示上上次解码方法总数,cur表示上次解码总数。假设当前解码方法数为sum,每次遍历初始化sum为0,若当前字符可以被单独解码,sun+=cur,否则sum+=0;若当前字符和上一个字符可以共同解码,sum+=pre,否则sum+=0。计算完之后,pre=cur,cur=sum ```cpp class Solution { public: From 0d871cfe3ff71b2a68b24923ea792b60e8526376 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 11:33:02 +0800 Subject: [PATCH 184/327] update ex7 --- 0.Tricky Problems.md | 112 ++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 61 deletions(-) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index de2af93..c285525 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -198,69 +198,59 @@ public: ``` Ex7:[Leetcode:Text Justification](http://oj.leetcode.com/problems/text-justification/) +对于每一行都贪婪的加入尽可能多的单词,然后对于多余的空格左对齐插入 ```java public class Solution { - public ArrayList fullJustify(String[] words, int L) { - // Start typing your Java solution below - // DO NOT write main() function - ArrayList result = new ArrayList(); - String[] spaces = new String[L+1]; - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < L+1; i++) { - spaces[i] = builder.toString(); - builder.append(' '); - } - - int len = words.length; - - int i = 0; - while (i < len) { - int j = i; - int total = words[i].length(); - while (true) { - j++; - if (j == len) break; - int w = words[j].length(); - if (total + w + 1 > L) break; - total += w + 1; - } - int left = L - total; - int c = j - i; - if (c == 1) { // single word - StringBuilder sb = new StringBuilder(words[i]); - sb.append(spaces[left]); - result.add(sb.toString()); - } - else { // multi-word - if (j == len) { // last line - StringBuilder sb = new StringBuilder(words[i]); - for (int x = i+1; x < j; x++) { - sb.append(' '); - sb.append(words[x]); - } - sb.append(spaces[left]); - result.add(sb.toString()); - } - else { - int k = left / (c - 1); // extra ' ' for every gap - int l = left - k * (c - 1); // count for first gaps with extra '' - StringBuilder sb = new StringBuilder(words[i]); - for (int x = i+1; x < j; x++) { - if (l > 0) { - sb.append(' '); - l--; - } - sb.append(' '); - sb.append(spaces[k]); - sb.append(words[x]); - } - result.add(sb.toString()); - } - } - i = j; - } - return result; - } + public static ArrayList fullJustify(String[] words, int L) { + ArrayList ret = new ArrayList(); + int wordsLen = words.length; // 单词数组的长度 + int curWordIdx = 0; // 处理第i个单词 + while(curWordIdx < wordsLen){ // 处理完所有单词后退出 + int charLen = 0; // 当前行累积的字符数量 + int probeWordIdx = curWordIdx; + while(probeWordIdx0){ // 因为居中对齐 + tmp += " "; + leftSpace--; + } + } + tmp += words[probeWordIdx-1]; // 处理当前行的最后一个单词 + if(leftSpace > 0){ // 因为左对齐,所以在最后补上剩下的空格 + tmp = addSpace(tmp, leftSpace); + } + ret.add(tmp); + curWordIdx = probeWordIdx; // 处理下一行的要处理的单词 + } + return ret; + } + + public static String addSpace(String s, int count){ + for(int i=1; i<=count; i++){ + s += " "; + } + return s; + } } ``` Ex8:[Leetcode:Max Points on a Line](http://oj.leetcode.com/problems/max-points-on-a-line/) From c34b8e87ccf8a40bd0ceefccf0e87cac824560eb Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 13:30:51 +0800 Subject: [PATCH 185/327] update ex8 --- 0.Tricky Problems.md | 1 + 1 file changed, 1 insertion(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index c285525..5d906f4 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -254,6 +254,7 @@ public class Solution { } ``` Ex8:[Leetcode:Max Points on a Line](http://oj.leetcode.com/problems/max-points-on-a-line/) +对于i j两个点,看点k是否在ij确定的直线上。有两种情况:1)该直线的斜率无法求出,则判断ijk三点横坐标是否相同;2)三点中任意两点直线斜率相同。避免重复计算:遍历点k时,先计算出后面需要用到的几个数。 ```cpp class Solution { public: From ba67ff148376cc94ddc6c58480f8fecc4aacdf26 Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 13:55:16 +0800 Subject: [PATCH 186/327] Update Ex9 --- 2.String dp and Array dp$keywords dp.md | 41 +++++++++++++++++-------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index fdaad55..1319cd2 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -465,19 +465,34 @@ public class MyOwn { ``` Ex9:[Leetcode:Distinct Subsequences](http://oj.leetcode.com/problems/distinct-subsequences/) +二维数组dp[i][j],用来记录匹配子序列的个数。 +* dp[0][0] = 1; T和S都是空串 +* dp[0][1 ... S.length() - 1] = 1; T是空串,S只有一种子序列匹配 +* dp[1 ... T.length() - 1][0] = 0; S是空串,T不是空串,S没有子序列匹配 +* dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0).1 <= i <= T.length(), 1 <= j <= S.length() ```cpp -class Solution { -public: +public class Solution { + public int numDistinct(String S, String T) { + // Start typing your Java solution below + // DO NOT write main() function + int[][] dp = new int[T.length() + 1][S.length() + 1]; + dp[0][0] = 1; + for (int i = 1; i <= T.length(); i++) { + dp[i][0] = 0; + } + for (int j = 1; j <= S.length(); j++) { + dp[0][j] = 1; + } + for (int i = 1; i <= T.length(); i++) { + for (int j = 1; j <= S.length(); j++) { + dp[i][j] = dp[i][j - 1]; + if (T.charAt(i - 1) == S.charAt(j - 1)) { + dp[i][j] += dp[i - 1][j - 1]; + } + } + } + return dp[T.length()][S.length()]; - int numDistinct(const string &S, const string &T) { - vector f(T.size() + 1); - f[0] = 1; - for (int i = 0; i < S.size(); ++i) { - for (int j = T.size() - 1; j >= 0; --j) { - f[j + 1] += S[i] == T[j] ? f[j] : 0; - } - } - return f[T.size()]; - } -}; + } +} ``` From ed40dcc9729c9e30b6a45a712b11c01f61a4462e Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 14:06:40 +0800 Subject: [PATCH 187/327] Update 2.String dp and Array dp$keywords dp.md --- 2.String dp and Array dp$keywords dp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 1319cd2..b90b20c 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -465,7 +465,7 @@ public class MyOwn { ``` Ex9:[Leetcode:Distinct Subsequences](http://oj.leetcode.com/problems/distinct-subsequences/) -二维数组dp[i][j],用来记录匹配子序列的个数。 +二维数组dp[T][S],用来记录匹配子序列的个数。 * dp[0][0] = 1; T和S都是空串 * dp[0][1 ... S.length() - 1] = 1; T是空串,S只有一种子序列匹配 * dp[1 ... T.length() - 1][0] = 0; S是空串,T不是空串,S没有子序列匹配 From c8f960706729899c3c1fd6ad62523c6bd004571c Mon Sep 17 00:00:00 2001 From: popolou Date: Fri, 7 Mar 2014 22:19:34 +0800 Subject: [PATCH 188/327] Update 8.Overwrite$keywords overwrite.md --- 8.Overwrite$keywords overwrite.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 957d28d..5154e8e 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -1,5 +1,6 @@ ###Overwrite$keywords overwrite Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) +从前向后比对 ```cpp class Solution { public: @@ -67,6 +68,7 @@ public: ``` Ex3:[Leetcode:Add Binary](http://oj.leetcode.com/problems/add-binary/) +记录标记位 ```cpp //add Binary @@ -166,6 +168,7 @@ public: }; ``` Ex5:[Leetcode:Pow(x, n)](http://oj.leetcode.com/problems/powx-n/) +二分法 ```cpp class Solution { public: @@ -191,6 +194,7 @@ public: ``` Ex6:[Leetcode:Sqrt(x)](http://oj.leetcode.com/problems/sqrtx/) +二分法 ```cpp class Solution { public: From ef56fedcafd70c68fc70b1c0712e2dfa0a813f97 Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 8 Mar 2014 11:00:25 +0800 Subject: [PATCH 189/327] Update 9.Sliding window$keywords window.md --- 9.Sliding window$keywords window.md | 55 ++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/9.Sliding window$keywords window.md b/9.Sliding window$keywords window.md index b0e84e1..c1d875c 100644 --- a/9.Sliding window$keywords window.md +++ b/9.Sliding window$keywords window.md @@ -30,7 +30,7 @@ public: } }; ``` -Ex2:[Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/) +Ex2:[Leetcode:Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/) ```cpp class Solution { public: @@ -53,3 +53,56 @@ public: } }; ``` +Ex3:[Leetcode:Substring with Concatenation of All Words](http://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/) +```java +public class Solution { + public ArrayList findSubstring(String S, String[] L) { + ArrayList list = new ArrayList(); + int wordLen = L[0].length(); + int numOfWords = L.length; + int length = wordLen * numOfWords; // substring length + if (S.length() < length) + return list; + + // initialize a hash map to facilitate the word match by word counting + HashMap map = new HashMap(); + for (String word : L) { + if (!map.containsKey(word)) { + map.put(word, 1); + } else { + map.put(word, map.get(word) + 1); + } + } + + for (int i = 0; i <= S.length() - length; i++) { + String substr = S.substring(i, i + length); + HashMap map2 = (HashMap) map + .clone(); + // partition the substring into the words of equal length + while (true) { + String word = substr.substring(0, wordLen); + if (map2.containsKey(word)) { + int num = map2.get(word) - 1; + // not found: too many occurrences + if (num < 0) { + break; + } + map2.put(word, num); + substr = substr.substring(wordLen); + // found + if (substr.isEmpty()) { + list.add(i); + break; + } + } + // not found: unmatched + else { + break; + } + } + } + + return list; + } +} +``` From 32c503d8f7a30137077e73f6df328be2397147d8 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:23:35 +0800 Subject: [PATCH 190/327] update Ex3 --- 6.Tree&keywords tree, transform, visit.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md index 0a65f3c..a5915e7 100644 --- a/6.Tree&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -126,6 +126,7 @@ Ex3:树中两个结点的最低公共祖先:给定一棵树,同时给出树 * 若右节点返回null,说明最低公共祖先在左边 * 若都不为null,说明当前节点为最低公共祖先 +Added by [@sc703bupt](https://github.com/sc703bupt):递归方法即是返回当前树是否存在两个节点的其中一个,当某个节点得到其两个子树都有目标节点时,其自身即为LCA。 ```cpp TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { if (root == NULL) @@ -134,12 +135,15 @@ TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { return root; TreeNode * left = getLCA(root->m_pLeft, X, Y); TreeNode * right = getLCA(root->m_pRight, X, Y); - if (left == NULL) - return right; - else if (right == NULL) - return left; - else - return root; + if(left == NULL && right == NULL){ + return NULL; + }else if (left == NULL){ + return right; + }else if (right == NULL){ + return left; + }else{ + return root; + } } ``` From d771e4d4e315cdf7ec6d40facb4c47f8f93ce0a7 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:44:26 +0800 Subject: [PATCH 191/327] move Ex1 to chapter 7 --- 9.Sliding window$keywords window.md | 38 ++++------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/9.Sliding window$keywords window.md b/9.Sliding window$keywords window.md index c1d875c..35f33b6 100644 --- a/9.Sliding window$keywords window.md +++ b/9.Sliding window$keywords window.md @@ -1,36 +1,8 @@ -###Sliding window$keywords window - -Ex1:[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/) -```cpp -class Solution { -public: +###9.Sliding window$keywords window +##*Sliding window - int longestValidParentheses(string s) { - int max_len = 0, last = -1; // the position of the last ')' - stack lefts; // keep track of the positions of non-matching '('s - for (int i = 0; i < s.size(); ++i) { - if (s[i] == '(') { - lefts.push(i); - } else { - if (lefts.empty()) { - // no matching left - last = i; - } else { - // find a matching pair - lefts.pop(); - if (lefts.empty()) { - max_len = max(max_len, i - last); - } else { - max_len = max(max_len, i - lefts.top()); - } - } - } - } - return max_len; - } -}; -``` -Ex2:[Leetcode:Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/) + +Ex1:[Leetcode:Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/) ```cpp class Solution { public: @@ -53,7 +25,7 @@ public: } }; ``` -Ex3:[Leetcode:Substring with Concatenation of All Words](http://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/) +Ex2:[Leetcode:Substring with Concatenation of All Words](http://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/) ```java public class Solution { public ArrayList findSubstring(String S, String[] L) { From 1172c50533f1d8b5e958c3ef804e228c8d37fffc Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:46:01 +0800 Subject: [PATCH 192/327] add Ex5 --- 7.Area Computation$keyword stack.md | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index dd43a59..745d710 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -192,3 +192,36 @@ public: } }; ``` + +Ex5:[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/) + +此题虽然不是计算面积类型题,但因其采用的解题思想与Ex3和Ex4十分相似,即使用一个栈来维护历史状态,故而放于此处。 + +```cpp +class Solution { +public: + + int longestValidParentheses(string s) { + int max_len = 0, last = -1; // the position of the last ')' + stack lefts; // keep track of the positions of non-matching '('s + for (int i = 0; i < s.size(); ++i) { + if (s[i] == '(') { + lefts.push(i); + } else { + if (lefts.empty()) { + // no matching left + last = i; + } else { + // find a matching pair + lefts.pop(); + if (lefts.empty()) { + max_len = max(max_len, i - last); + } else { + max_len = max(max_len, i - lefts.top()); + } + } + } + } + return max_len; + } +}; From 8a9d24ac9e32198b14d12519dd59b98c95350836 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:49:39 +0800 Subject: [PATCH 193/327] revise title --- 8.Overwrite$keywords overwrite.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/8.Overwrite$keywords overwrite.md b/8.Overwrite$keywords overwrite.md index 5154e8e..8fa50ff 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Overwrite$keywords overwrite.md @@ -1,6 +1,9 @@ -###Overwrite$keywords overwrite -Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) +###8.Overwrite$keywords overwrite +##*Overwrite +Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) + 从前向后比对 + ```cpp class Solution { public: From e0269fe7f49549bcce65d26c43995ea1430402bb Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:51:35 +0800 Subject: [PATCH 194/327] revise title --- ...keywords overwrite.md => 8.Rewrite STL$keywords rewrite.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename 8.Overwrite$keywords overwrite.md => 8.Rewrite STL$keywords rewrite.md (99%) diff --git a/8.Overwrite$keywords overwrite.md b/8.Rewrite STL$keywords rewrite.md similarity index 99% rename from 8.Overwrite$keywords overwrite.md rename to 8.Rewrite STL$keywords rewrite.md index 8fa50ff..54c8c71 100644 --- a/8.Overwrite$keywords overwrite.md +++ b/8.Rewrite STL$keywords rewrite.md @@ -1,5 +1,5 @@ -###8.Overwrite$keywords overwrite -##*Overwrite +##8.Rewrite STL$keywords Rewrite +###*Rewrite STL Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) 从前向后比对 From 5468634284d73c1335bdf405e31e24eab6e63cd4 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:52:15 +0800 Subject: [PATCH 195/327] revise title --- 9.Sliding window$keywords window.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/9.Sliding window$keywords window.md b/9.Sliding window$keywords window.md index 35f33b6..4307c5f 100644 --- a/9.Sliding window$keywords window.md +++ b/9.Sliding window$keywords window.md @@ -1,6 +1,5 @@ -###9.Sliding window$keywords window -##*Sliding window - +##9.Sliding window$keywords window +###*Sliding window Ex1:[Leetcode:Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/) ```cpp From 96da0be7214de22222959a1b777865b96978b96a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:53:11 +0800 Subject: [PATCH 196/327] revise chapter 8 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96fa33c..08c31da 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Chapters 5.[Graph](5.Graph&keywords graph.md)$keywords graph 6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search 7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack -8.[Overwrite](8.Overwrite$keywords overwrite.md)$keywords overwrite +8.[Rewrite STL](8.Rewrite STL$keywords Rewrite.md)$keywords Rewrite 9.[Sliding window](9.Sliding window$keywords window.md)$keywords window 10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata Core contributors From 4491487cc8e83ac7334097744bbfe7ab9a9919b3 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 21:53:37 +0800 Subject: [PATCH 197/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08c31da..452bff0 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Chapters 5.[Graph](5.Graph&keywords graph.md)$keywords graph 6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search 7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack -8.[Rewrite STL](8.Rewrite STL$keywords Rewrite.md)$keywords Rewrite +8.[Rewrite STL](8.Rewrite STL$keywords Rewrite.md)$keywords Rewrite 9.[Sliding window](9.Sliding window$keywords window.md)$keywords window 10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata Core contributors From 0362d1bb7e47b132983a28294f71e89015a806d7 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 22:05:53 +0800 Subject: [PATCH 198/327] Create 11.String$keywords string.md --- 11.String$keywords string.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 11.String$keywords string.md diff --git a/11.String$keywords string.md b/11.String$keywords string.md new file mode 100644 index 0000000..a4d2d17 --- /dev/null +++ b/11.String$keywords string.md @@ -0,0 +1,5 @@ +##11.String$keywords string +###*String +尽管已经有了[2.String dp and Array dp](2.String dp and Array dp$keywords dp.md)介绍一些字符串的处理 + +1.Ex1 From c50909c5e3b98574bcb632aa704f0b3298f1c5c6 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 22:07:12 +0800 Subject: [PATCH 199/327] add chapter 11 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 452bff0..586976d 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Chapters 8.[Rewrite STL](8.Rewrite STL$keywords Rewrite.md)$keywords Rewrite 9.[Sliding window](9.Sliding window$keywords window.md)$keywords window 10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata +11.[String$keywords string](11.String$keywords string.md) Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 350cb8f17825c7f80e194bcbb7bd003f57937772 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 22:07:37 +0800 Subject: [PATCH 200/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 586976d..939fd87 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Chapters 8.[Rewrite STL](8.Rewrite STL$keywords Rewrite.md)$keywords Rewrite 9.[Sliding window](9.Sliding window$keywords window.md)$keywords window 10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata -11.[String$keywords string](11.String$keywords string.md) +11.[String](11.String$keywords string.md)$keywords string Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From d5b5346eba665026820f348b2f142b32e1c8e136 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 22:13:41 +0800 Subject: [PATCH 201/327] update Ex2, move Ex3,Ex4,Ex7 to chapter 11 --- 0.Tricky Problems.md | 146 +++++++------------------------------------ 1 file changed, 21 insertions(+), 125 deletions(-) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 5d906f4..78f52ea 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -45,91 +45,43 @@ public: } }; ``` -Ex2:[leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/) -二进制转格雷码:gray = (binary) xor (binary >> 1) +Ex2:[leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/) +一个普通解法: ```cpp class Solution { public: - vector grayCode(int n) { - vector vec; - int size = 1 << n; - for (int i = 0; i < size; i++) { - vec.push_back(i^(i >> 1)); - } - return vec; - } -}; -``` - -Ex3:[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/) -每次首先判断p当前字符的下一个字符是不是* -* 不是\*,如果s和p的当前字符相同,判断s和p的下一位 -* 是\*,若p的当前字符是'.',则可以匹配到s的末尾;否则,用p的当前字符一直去匹配s,若p当前字符等于s当前字符,判断若p重复0次s和p是否能匹配;若能则跳出循环,若不能,用p当前字符继续匹配s的下一位。当p的当前字符终于和s的当前字符不相等时,则返回p后面的字符串和s是否匹配 -```cpp -class Solution { -public: - - bool isMatch(const char *s, const char *p) { - if (*p == '\0') return *s == '\0'; - // next char is not '*', then must match current character - if (*(p + 1) != '*') { - if (*p == *s || (*p == '.' && *s != '\0')) - return isMatch(s + 1, p + 1); - else - return false; - } else { // next char is '*' - while (*p == *s || (*p == '.' && *s != '\0')) { - if (isMatch(s, p + 2)) - return true; - s++; + vector result; + result.push_back(0); + if(n <= 0) return result; + int multiplier = 1; + for(int i = 0;i=0;j--){ + result.push_back(result.at(j)+multiplier); } - return isMatch(s, p + 2); + multiplier <<= 1; } + return result; } }; ``` - -Ex4:[Leetcode:Simplify Path](http://oj.leetcode.com/problems/simplify-path/) -在每次碰到/之前,都将前面的字符串保存起来;碰到/或者遍历到路径结束,若字符串为'..',表示上一目录;若为'.',表示当前目录;其余情况保存路径,然后重新记录。 +技巧性较强的解法,二进制转格雷码:gray = (binary) xor (binary >> 1) ```cpp class Solution { public: - string simplifyPath(string path) { - // Start typing your C/C++ solution below - // DO NOT write int main() function - vector pathes; - string seg = ""; - for (int i = 0; i <= path.size(); ++i) { - if (i == path.size() || path[i] == '/') { - if (seg == "..") { - if (pathes.size() > 0) { - pathes.pop_back(); - } else { - //return "/";//error, in the test set, this case just ignore - } - } else if (seg == ".") { - //do nothing - } else if (seg.size() > 0) { - pathes.push_back(seg); - } - seg = ""; - } else { - seg += path[i]; - } - } - string ret = "/"; - for (int i = 0; i < pathes.size(); ++i) { - if (i > 0) ret += "/"; - ret += pathes[i]; + vector grayCode(int n) { + vector vec; + int size = 1 << n; + for (int i = 0; i < size; i++) { + vec.push_back(i^(i >> 1)); } - return ret; + return vec; } }; ``` -Ex5:[Leetcode:Evaluate Reverse Polish Notation](http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/) +Ex3:[Leetcode:Evaluate Reverse Polish Notation](http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/) 一个栈保存操作数,当遇到操作符是,弹出两个操作数,计算完后将结果压入栈 ```java public class Solution { @@ -172,7 +124,7 @@ public class Solution { } } ``` -Ex6:[Leetcode:Decode Ways](http://oj.leetcode.com/problems/decode-ways/) +Ex4:[Leetcode:Decode Ways](http://oj.leetcode.com/problems/decode-ways/) 每次遍历时,pre表示上上次解码方法总数,cur表示上次解码总数。假设当前解码方法数为sum,每次遍历初始化sum为0,若当前字符可以被单独解码,sun+=cur,否则sum+=0;若当前字符和上一个字符可以共同解码,sum+=pre,否则sum+=0。计算完之后,pre=cur,cur=sum ```cpp class Solution { @@ -197,63 +149,7 @@ public: }; ``` -Ex7:[Leetcode:Text Justification](http://oj.leetcode.com/problems/text-justification/) -对于每一行都贪婪的加入尽可能多的单词,然后对于多余的空格左对齐插入 -```java -public class Solution { - public static ArrayList fullJustify(String[] words, int L) { - ArrayList ret = new ArrayList(); - int wordsLen = words.length; // 单词数组的长度 - int curWordIdx = 0; // 处理第i个单词 - while(curWordIdx < wordsLen){ // 处理完所有单词后退出 - int charLen = 0; // 当前行累积的字符数量 - int probeWordIdx = curWordIdx; - while(probeWordIdx0){ // 因为居中对齐 - tmp += " "; - leftSpace--; - } - } - tmp += words[probeWordIdx-1]; // 处理当前行的最后一个单词 - if(leftSpace > 0){ // 因为左对齐,所以在最后补上剩下的空格 - tmp = addSpace(tmp, leftSpace); - } - ret.add(tmp); - curWordIdx = probeWordIdx; // 处理下一行的要处理的单词 - } - return ret; - } - - public static String addSpace(String s, int count){ - for(int i=1; i<=count; i++){ - s += " "; - } - return s; - } -} -``` -Ex8:[Leetcode:Max Points on a Line](http://oj.leetcode.com/problems/max-points-on-a-line/) +Ex5:[Leetcode:Max Points on a Line](http://oj.leetcode.com/problems/max-points-on-a-line/) 对于i j两个点,看点k是否在ij确定的直线上。有两种情况:1)该直线的斜率无法求出,则判断ijk三点横坐标是否相同;2)三点中任意两点直线斜率相同。避免重复计算:遍历点k时,先计算出后面需要用到的几个数。 ```cpp class Solution { From 408495690e5eea5657a58049a2765b3be5f5c228 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 22:14:13 +0800 Subject: [PATCH 202/327] add Ex1,Ex2,Ex3 --- 11.String$keywords string.md | 127 ++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/11.String$keywords string.md b/11.String$keywords string.md index a4d2d17..9acdccf 100644 --- a/11.String$keywords string.md +++ b/11.String$keywords string.md @@ -1,5 +1,128 @@ ##11.String$keywords string ###*String -尽管已经有了[2.String dp and Array dp](2.String dp and Array dp$keywords dp.md)介绍一些字符串的处理 +尽管已经有了[2.String dp and Array dp](2.String dp and Array dp$keywords dp.md)介绍一些字符串问题的处理方法,但都是基于dp方法。本章收录多种字符串的处理方法。 -1.Ex1 +Ex1:[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/) +每次首先判断p当前字符的下一个字符是不是* +* 不是*,如果s和p的当前字符相同,判断s和p的下一位 +* 是*,若p的当前字符是'.',则可以匹配到s的末尾;否则,用p的当前字符一直去匹配s,若p当前字符等于s当前字符,判断若p重复0次s和p是否能匹配;若能则跳出循环,若不能,用p当前字符继续匹配s的下一位。当p的当前字符终于和s的当前字符不相等时,则返回p后面的字符串和s是否匹配 + +```cpp +class Solution { +public: + + bool isMatch(const char *s, const char *p) { + if (*p == '\0') return *s == '\0'; + // next char is not '*', then must match current character + if (*(p + 1) != '*') { + if (*p == *s || (*p == '.' && *s != '\0')) + return isMatch(s + 1, p + 1); + else + return false; + } else { // next char is '*' + while (*p == *s || (*p == '.' && *s != '\0')) { + if (isMatch(s, p + 2)) + return true; + s++; + } + return isMatch(s, p + 2); + } + } +}; +``` + +Ex2:[Leetcode:Simplify Path](http://oj.leetcode.com/problems/simplify-path/) +在每次碰到/之前,都将前面的字符串保存起来;碰到/或者遍历到路径结束,若字符串为'..',表示上一目录;若为'.',表示当前目录;其余情况保存路径,然后重新记录。 +```cpp +class Solution { +public: + + string simplifyPath(string path) { + // Start typing your C/C++ solution below + // DO NOT write int main() function + vector pathes; + string seg = ""; + for (int i = 0; i <= path.size(); ++i) { + if (i == path.size() || path[i] == '/') { + if (seg == "..") { + if (pathes.size() > 0) { + pathes.pop_back(); + } else { + //return "/";//error, in the test set, this case just ignore + } + } else if (seg == ".") { + //do nothing + } else if (seg.size() > 0) { + pathes.push_back(seg); + } + seg = ""; + } else { + seg += path[i]; + } + } + string ret = "/"; + for (int i = 0; i < pathes.size(); ++i) { + if (i > 0) ret += "/"; + ret += pathes[i]; + } + return ret; + } +}; +``` + +Ex3:[Leetcode:Text Justification](http://oj.leetcode.com/problems/text-justification/) +对于每一行都贪婪的加入尽可能多的单词,然后对于多余的空格左对齐插入 +```java +public class Solution { + public static ArrayList fullJustify(String[] words, int L) { + ArrayList ret = new ArrayList(); + int wordsLen = words.length; // 单词数组的长度 + int curWordIdx = 0; // 处理第i个单词 + while(curWordIdx < wordsLen){ // 处理完所有单词后退出 + int charLen = 0; // 当前行累积的字符数量 + int probeWordIdx = curWordIdx; + while(probeWordIdx0){ // 因为居中对齐 + tmp += " "; + leftSpace--; + } + } + tmp += words[probeWordIdx-1]; // 处理当前行的最后一个单词 + if(leftSpace > 0){ // 因为左对齐,所以在最后补上剩下的空格 + tmp = addSpace(tmp, leftSpace); + } + ret.add(tmp); + curWordIdx = probeWordIdx; // 处理下一行的要处理的单词 + } + return ret; + } + + public static String addSpace(String s, int count){ + for(int i=1; i<=count; i++){ + s += " "; + } + return s; + } +} +``` From 6bb437a090fc772999815171b6efaa184b794754 Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 8 Mar 2014 22:16:34 +0800 Subject: [PATCH 203/327] Rename 10. Big Data Processing$keywords Bigdata.md to 10.Big Data Processing$keywords Bigdata.md --- ...words Bigdata.md => 10.Big Data Processing$keywords Bigdata.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 10. Big Data Processing$keywords Bigdata.md => 10.Big Data Processing$keywords Bigdata.md (100%) diff --git a/10. Big Data Processing$keywords Bigdata.md b/10.Big Data Processing$keywords Bigdata.md similarity index 100% rename from 10. Big Data Processing$keywords Bigdata.md rename to 10.Big Data Processing$keywords Bigdata.md From 99536a610b0100cf35d77cf23d945d15753e87d0 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 22:41:22 +0800 Subject: [PATCH 204/327] move Ex9 to Chapter 11 --- 4.Search Array$keywords search.md | 52 ------------------------------- 1 file changed, 52 deletions(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index d4774a7..31d736a 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -368,55 +368,3 @@ private: } }; ``` - -Ex9:[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/) -普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。之后长度若能扩展则继续扩展。然后根据i更新最右R。 -```cpp -class Solution { -public: - // Transform S into T. - // For example, S = "abba", T = "^#a#b#b#a#$". - // ^ and $ signs are sentinels appended to each end to avoid bounds checking - - string preProcess(string s) { - int n = s.length(); - if (n == 0) return "^$"; - string ret = "^"; - for (int i = 0; i < n; i++) ret += "#" + s.substr(i, 1); - ret += "#$"; - return ret; - } - - string longestPalindrome(string s) { - string T = preProcess(s); - const int n = T.length(); - // 以T[i] 为中心,向左/右扩张的长度,不包含T[i] 自己, - // 因此P[i] 是源字符串中回文串的长度 - int P[n]; - int C = 0, R = 0; - for (int i = 1; i < n - 1; i++) { - int i_mirror = 2 * C - i; // equals to i' = C - (i-C) - P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; - // Attempt to expand palindrome centered at i - while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) - P[i]++; - // If palindrome centered at i expand past R, - // adjust center based on expanded palindrome. - if (i + P[i] > R) { - C = i; - R = i + P[i]; - } - } - // Find the maximum element in P. - int max_len = 0; - int center_index = 0; - for (int i = 1; i < n - 1; i++) { - if (P[i] > max_len) { - max_len = P[i]; - center_index = i; - } - } - return s.substr((center_index - 1 - max_len) / 2, max_len); - } -}; -``` From 592a116efdf79873be2198137aaf44e086af1429 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 8 Mar 2014 22:42:20 +0800 Subject: [PATCH 205/327] add Ex4 --- 11.String$keywords string.md | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/11.String$keywords string.md b/11.String$keywords string.md index 9acdccf..6219d70 100644 --- a/11.String$keywords string.md +++ b/11.String$keywords string.md @@ -126,3 +126,55 @@ public class Solution { } } ``` + +Ex4:[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/) +普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。之后长度若能扩展则继续扩展。然后根据i更新最右R。 +```cpp +class Solution { +public: + // Transform S into T. + // For example, S = "abba", T = "^#a#b#b#a#$". + // ^ and $ signs are sentinels appended to each end to avoid bounds checking + + string preProcess(string s) { + int n = s.length(); + if (n == 0) return "^$"; + string ret = "^"; + for (int i = 0; i < n; i++) ret += "#" + s.substr(i, 1); + ret += "#$"; + return ret; + } + + string longestPalindrome(string s) { + string T = preProcess(s); + const int n = T.length(); + // 以T[i] 为中心,向左/右扩张的长度,不包含T[i] 自己, + // 因此P[i] 是源字符串中回文串的长度 + int P[n]; + int C = 0, R = 0; + for (int i = 1; i < n - 1; i++) { + int i_mirror = 2 * C - i; // equals to i' = C - (i-C) + P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; + // Attempt to expand palindrome centered at i + while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) + P[i]++; + // If palindrome centered at i expand past R, + // adjust center based on expanded palindrome. + if (i + P[i] > R) { + C = i; + R = i + P[i]; + } + } + // Find the maximum element in P. + int max_len = 0; + int center_index = 0; + for (int i = 1; i < n - 1; i++) { + if (P[i] > max_len) { + max_len = P[i]; + center_index = i; + } + } + return s.substr((center_index - 1 - max_len) / 2, max_len); + } +}; +``` From f96c5691f4e9beb6fdae92f4aea50dd6e06c1c91 Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 9 Mar 2014 10:36:36 +0800 Subject: [PATCH 206/327] Update 8.Rewrite STL$keywords rewrite.md --- 8.Rewrite STL$keywords rewrite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8.Rewrite STL$keywords rewrite.md b/8.Rewrite STL$keywords rewrite.md index 54c8c71..b49d2d6 100644 --- a/8.Rewrite STL$keywords rewrite.md +++ b/8.Rewrite STL$keywords rewrite.md @@ -2,7 +2,7 @@ ###*Rewrite STL Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) -从前向后比对 +从前向后比对,实现 ```cpp class Solution { From be792476f009c272ed2ed23f37108df62ff8a003 Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 9 Mar 2014 10:37:40 +0800 Subject: [PATCH 207/327] Update 0.Tricky Problems.md --- 0.Tricky Problems.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 78f52ea..8872e19 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -45,7 +45,7 @@ public: } }; ``` -Ex2:[leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/) +Ex2:[leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/) 一个普通解法: ```cpp class Solution { From cbb1429ff74caf991b39f7ef736ded0c5e2610cd Mon Sep 17 00:00:00 2001 From: popolou Date: Sun, 9 Mar 2014 10:38:41 +0800 Subject: [PATCH 208/327] Update 0.Tricky Problems.md --- 0.Tricky Problems.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index 8872e19..e149283 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -82,7 +82,7 @@ public: ``` Ex3:[Leetcode:Evaluate Reverse Polish Notation](http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/) -一个栈保存操作数,当遇到操作符是,弹出两个操作数,计算完后将结果压入栈 +一个栈保存操作数,当遇到操作符时,弹出两个操作数,计算完后将结果压入栈 ```java public class Solution { public int evalRPN(String[] tokens) { From 0d9a5963da6d0dca50506e065b8fd996e721f7f0 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 10 Mar 2014 16:45:53 +0800 Subject: [PATCH 209/327] Update Ex7 --- 5.Graph&keywords graph.md | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md index 4b23ff6..b76b19e 100644 --- a/5.Graph&keywords graph.md +++ b/5.Graph&keywords graph.md @@ -347,3 +347,100 @@ int main() return 0; } ``` + +Ex7:拓扑排序:拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。 +首先收集所有入度为0的顶点。将入度为0的顶点加入结果集。之后移除这个顶点连接的所有边,加入入度为零的顶点,如此循环。若加入结果集的节点个数少于总个数,说明有环,无法导出拓扑序列 +```cpp + + #include + #include + #include + #include + using namespace std; + //toposort的三种情况 + const int N=27; + int n,m; + int graph[N][N],indegree[N],list[N]; + + int toposort(int n) + { + int in[N]; + memcpy(in,indegree,sizeof(indegree)); //复制入度数组,以免对主函数中的indegree有影响 + stack s; + int i; + for(i=0;i1) + flag=1; //序列不确定 + t=s.top(); + s.pop(); + list[j++]=t; //记录出栈的数字 + for(i=0;i Date: Mon, 10 Mar 2014 17:06:23 +0800 Subject: [PATCH 210/327] update ex8 --- 8.Rewrite STL$keywords rewrite.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/8.Rewrite STL$keywords rewrite.md b/8.Rewrite STL$keywords rewrite.md index b49d2d6..aa029a6 100644 --- a/8.Rewrite STL$keywords rewrite.md +++ b/8.Rewrite STL$keywords rewrite.md @@ -257,3 +257,20 @@ public: } }; ``` +Ex8:strcpy +```cpp +char * strcpy(char * strDest, const char * strSrc) + { + + if ((strDest == NULL) || (strSrc == NULL)) + + throw "Invalid argument(s)"; + + char * strDestCopy = strDest; + + while ((*strDest++ = *strSrc++) != '\0'); + + return strDestCopy; + +} +``` From 7d03129edead69550edd585c9071722a5e56b643 Mon Sep 17 00:00:00 2001 From: popolou Date: Mon, 10 Mar 2014 20:20:34 +0800 Subject: [PATCH 211/327] Update Ex3 --- 10.Big Data Processing$keywords Bigdata.md | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/10.Big Data Processing$keywords Bigdata.md b/10.Big Data Processing$keywords Bigdata.md index 7e504e9..7d13d18 100644 --- a/10.Big Data Processing$keywords Bigdata.md +++ b/10.Big Data Processing$keywords Bigdata.md @@ -20,3 +20,61 @@ **Ex2:给定100G条IP数据以及一张划分IP域的表,使用最快的方法统计出每个IP域的IP个数。** IP由32位组成,共4G个,因此100G条IP必然存在重复,考虑使用一个MAP进行压缩,压缩比达到25:1。又因为划分IP域的表的是单调递增的,如果使用一个有序的MAP,则可以在遍历MAP的同时统计出所有结果。 + + +**Ex3:Bit-map** +所谓的Bit-map就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省空间 +```cpp +//定义每个Byte中有8个Bit位 +#include +#define BYTESIZE 8 + +void SetBit(char *p, int posi) { + for (int i = 0; i < (posi / BYTESIZE); i++) { + p++; + } + + *p = *p | (0x01<<(posi % BYTESIZE)); //将该Bit位赋值1 + return; +} + +void BitMapSortDemo() { + //为了简单起见,我们不考虑负数 + int num[] = {3, 5, 2, 10, 6, 12, 8, 14, 9}; + + //BufferLen这个值是根据待排序的数据中最大值确定的 + //待排序中的最大值是14,因此只需要2个Bytes(16个Bit) + //就可以了。 + const int BufferLen = 2; + char *pBuffer = new char[BufferLen]; + + //要将所有的Bit位置为0,否则结果不可预知。 + memset(pBuffer, 0, BufferLen); + for (int i = 0; i<9; i++) { + //首先将相应Bit位上置为1 + SetBit(pBuffer, num[i]); + } + + //输出排序结果 + for (int i = 0; i Date: Mon, 10 Mar 2014 22:19:40 +0800 Subject: [PATCH 212/327] update ex5 --- 11.String$keywords string.md | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/11.String$keywords string.md b/11.String$keywords string.md index 6219d70..fcc44c1 100644 --- a/11.String$keywords string.md +++ b/11.String$keywords string.md @@ -178,3 +178,59 @@ public: } }; ``` + +Ex5:KMP算法 +即字符串匹配问题。首先要算出字符串的覆盖数组,当发生在j长度失配时,只要把pattern向右移动j-overlay(j)长度就可以了。 + +```cpp +#include +#include +#include +using namespace std; + +int kmp_find(const string& target, const string& pattern) { + const int target_length = target.size(); + const int pattern_length = pattern.size(); + int * overlay_value = new int[pattern_length]; + overlay_value[0] = -1; + int index = 0; + for (int i = 1; i < pattern_length; ++i) { + index = overlay_value[i - 1]; + while (index >= 0 && pattern[index + 1] != pattern[i]) { + index = overlay_value[index]; + } + if (pattern[index + 1] == pattern[i]) { + overlay_value[i] = index + 1; + } else { + overlay_value[i] = -1; + } + } + //match algorithm start + int pattern_index = 0; + int target_index = 0; + while (pattern_index < pattern_length && target_index < target_length) { + if (target[target_index] == pattern[pattern_index]) { + ++target_index; + ++pattern_index; + } else if (pattern_index == 0) { + ++target_index; + } else { + pattern_index = overlay_value[pattern_index - 1] + 1; + } + } + if (pattern_index == pattern_length) { + return target_index - pattern_index; + } else { + return -1; + } + delete [] overlay_value; +} + +int main() { + string source = " annbcdanacadsannannabnna"; + string pattern = " annacanna"; + cout << kmp_find(source, pattern) << endl; + return 0; +} + +``` From 837db22bab1d1785fbee060726045e880817d09d Mon Sep 17 00:00:00 2001 From: popolou Date: Tue, 11 Mar 2014 09:00:41 +0800 Subject: [PATCH 213/327] create Greedy$keywords greedy --- Greedy$keywords greedy.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Greedy$keywords greedy.md diff --git a/Greedy$keywords greedy.md b/Greedy$keywords greedy.md new file mode 100644 index 0000000..f72b972 --- /dev/null +++ b/Greedy$keywords greedy.md @@ -0,0 +1 @@ +###Greedy$keywords greedy From ccd08940b6d127197d34356e4cd4f3bdef45248e Mon Sep 17 00:00:00 2001 From: popolou Date: Tue, 11 Mar 2014 09:01:00 +0800 Subject: [PATCH 214/327] Rename Greedy$keywords greedy.md to 12.Greedy$keywords greedy.md --- Greedy$keywords greedy.md => 12.Greedy$keywords greedy.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Greedy$keywords greedy.md => 12.Greedy$keywords greedy.md (100%) diff --git a/Greedy$keywords greedy.md b/12.Greedy$keywords greedy.md similarity index 100% rename from Greedy$keywords greedy.md rename to 12.Greedy$keywords greedy.md From 47d8377a6e4fced4eb1b944191d3e925ff001935 Mon Sep 17 00:00:00 2001 From: popolou Date: Tue, 11 Mar 2014 09:12:35 +0800 Subject: [PATCH 215/327] update ex1 --- 12.Greedy$keywords greedy.md | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/12.Greedy$keywords greedy.md b/12.Greedy$keywords greedy.md index f72b972..a302399 100644 --- a/12.Greedy$keywords greedy.md +++ b/12.Greedy$keywords greedy.md @@ -1 +1,53 @@ ###Greedy$keywords greedy +Ex1:一个n位的数,去掉其中的k位,问怎样去使得留下来的(n-k)位数按原来的前后顺序组成的数最小 +贪心算法,在每次被访问的位置保证有最优解。求一共n位,求其中的m位组成的数最小。那么这个m位的数,最高位应该在原数的最高位到第m位区间找,要不然就不能当第m位了,其余依次递推 +```cpp +#include +#include +#include +using namespace std; +int *q; + +int findMinIndex(int arr[], int beg, int end) //[] +{ + if(beg > end) + return -1; + int minv = arr[beg]; + int minIndex = beg; + for(int i = beg + 1; i <= end; ++i) + { + if(arr[i] < minv) + { + minv = arr[i]; + minIndex = i; + } + } + return minIndex; +} + +int getRemain(int arr[], int size, int k) +{ + assert(size > k && k >= 0); + int rev = 0, revIndex = -1; + for(int i = size - k; i < size; ++i) + { + revIndex = findMinIndex(arr, revIndex + 1, i); + rev = rev * 10 + arr[revIndex]; + } + return rev; +} + +int main() +{ + int arr[] = {3, 1, 6, 4, 8, 5, 7}; + size_t size = sizeof(arr) / sizeof(int); + + int remainNum; + for (int k = size-1; k > 0; --k) + { + int remainNum = getRemain(arr, size, size - k); + cout << "When k = " << k << ", the remaining value is:" << remainNum << endl; + } + +} +``` From d8bb9694a8d4de5794b5dc04ae32cccaa95828c3 Mon Sep 17 00:00:00 2001 From: popolou Date: Tue, 11 Mar 2014 09:15:46 +0800 Subject: [PATCH 216/327] Update 12.Greedy$keywords greedy.md --- 12.Greedy$keywords greedy.md | 1 - 1 file changed, 1 deletion(-) diff --git a/12.Greedy$keywords greedy.md b/12.Greedy$keywords greedy.md index a302399..93105e9 100644 --- a/12.Greedy$keywords greedy.md +++ b/12.Greedy$keywords greedy.md @@ -27,7 +27,6 @@ int findMinIndex(int arr[], int beg, int end) //[] int getRemain(int arr[], int size, int k) { - assert(size > k && k >= 0); int rev = 0, revIndex = -1; for(int i = size - k; i < size; ++i) { From dda286bb7bc07ded3236cc7a3e2e4869828cfc0d Mon Sep 17 00:00:00 2001 From: popolou Date: Tue, 11 Mar 2014 09:19:41 +0800 Subject: [PATCH 217/327] Update 12.Greedy$keywords greedy.md --- 12.Greedy$keywords greedy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/12.Greedy$keywords greedy.md b/12.Greedy$keywords greedy.md index 93105e9..47697ec 100644 --- a/12.Greedy$keywords greedy.md +++ b/12.Greedy$keywords greedy.md @@ -44,7 +44,7 @@ int main() int remainNum; for (int k = size-1; k > 0; --k) { - int remainNum = getRemain(arr, size, size - k); + remainNum = getRemain(arr, size, size - k); cout << "When k = " << k << ", the remaining value is:" << remainNum << endl; } From 1c17200f936e665fca4f2d67805ed4a12fd36866 Mon Sep 17 00:00:00 2001 From: popolou Date: Tue, 11 Mar 2014 09:29:53 +0800 Subject: [PATCH 218/327] Update 12.Greedy$keywords greedy.md --- 12.Greedy$keywords greedy.md | 1 - 1 file changed, 1 deletion(-) diff --git a/12.Greedy$keywords greedy.md b/12.Greedy$keywords greedy.md index 47697ec..8291da0 100644 --- a/12.Greedy$keywords greedy.md +++ b/12.Greedy$keywords greedy.md @@ -6,7 +6,6 @@ Ex1:一个n位的数,去掉其中的k位,问怎样去使得留下来的(n- #include #include using namespace std; -int *q; int findMinIndex(int arr[], int beg, int end) //[] { From f22b20b5d2343b50e5d8be4e61dffe6036c697af Mon Sep 17 00:00:00 2001 From: popolou Date: Tue, 11 Mar 2014 09:31:10 +0800 Subject: [PATCH 219/327] Update 12.Greedy$keywords greedy.md --- 12.Greedy$keywords greedy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/12.Greedy$keywords greedy.md b/12.Greedy$keywords greedy.md index 8291da0..2a3b33d 100644 --- a/12.Greedy$keywords greedy.md +++ b/12.Greedy$keywords greedy.md @@ -7,7 +7,7 @@ Ex1:一个n位的数,去掉其中的k位,问怎样去使得留下来的(n- #include using namespace std; -int findMinIndex(int arr[], int beg, int end) //[] +int findMinIndex(int arr[], int beg, int end) { if(beg > end) return -1; From 4bbcef477538a69e6f3864c0dd7c7f3936e22cc9 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 11 Mar 2014 16:33:28 +0800 Subject: [PATCH 220/327] Create 13.Java$keywords java.md --- 13.Java$keywords java.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 13.Java$keywords java.md diff --git a/13.Java$keywords java.md b/13.Java$keywords java.md new file mode 100644 index 0000000..027d3ba --- /dev/null +++ b/13.Java$keywords java.md @@ -0,0 +1,4 @@ +##Java +###*与C++的一些不同之处 + +###*Java重要知识点 From dfb732b63f169bfb7888f26c0dddfd5a54354e57 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 11 Mar 2014 16:38:12 +0800 Subject: [PATCH 221/327] add chapter 12 and 13 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 939fd87..fec4f8d 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ Chapters 9.[Sliding window](9.Sliding window$keywords window.md)$keywords window 10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata 11.[String](11.String$keywords string.md)$keywords string +12.[Greedy](12.Greedy$keywords greedy.md)$keywords greedy +13.[Java](Java$keywords java.md)$keywords java + Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From dfe8ce51e734a6fa05a4bf4b655d163a5dd47b0b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 11 Mar 2014 22:57:24 +0800 Subject: [PATCH 222/327] Update 13.Java$keywords java.md --- 13.Java$keywords java.md | 108 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/13.Java$keywords java.md b/13.Java$keywords java.md index 027d3ba..717deb1 100644 --- a/13.Java$keywords java.md +++ b/13.Java$keywords java.md @@ -1,4 +1,112 @@ ##Java +严格的说本章不应收录在本github项目中,但考虑到语言本身对于算法的实现也是有影响,现将一些较为重要和较难记忆理解的Java知识收录此处共查阅学习。 ###*与C++的一些不同之处 +1.char类型的宽度为16bit;c++为8bit +2.没有unsigned修饰符;c++有 +3.下列代码是非法的;c++合法 + int x = 12; + { + int x = 13; + } +4.String s;并没有创建一个对象,只是声明了一个引用;c++在栈上创建了一个对象 +5.类成员会获得默认值;c++不会自动初始化类成员 +6.类成员可以直接初始化;c++的类成员不能直接初始化,可以在构造函数里初始化 +7.对于对象参数,默认为传引用;c++默认为传值 +8.=号赋值只是使新的引用指向了旧的对象,也即新旧引用指向同一个对象;c++则会生成一个新的对象 +9.>>>号是高位补0右移运算符;c++无此符号 +10.拥有finalize()方法;c++只有析构函数 +11.可以使用int[] A或int A[]方式声明一个数组,因为是引用,不可以指定数组大小;c++只能使用int A[]的方式,可以指定数组大小 +12.默认开启动态绑定;C++使用virtual关键字才能开启动态绑定 ###*Java重要知识点 +1.java.lang是默认导入每个java文件的 +2.equals()默认行为是比较引用,可以重写;==判断的是引用的内存地址是否相同 +3.对byte和short的位移操作要特别小心,它们会被转换为int型然后位移,这会导致不正确的结果 +4.bool类型不允许任何类型转换,也不允许使用类似while(1)的语句,0,1并不等同于false和true,必须使用while(true) +5.float或double转为整形值时,总是对该数字进行截尾 +6.提升:对基本数据类型进行算术运算或按位运算时,低于int型的数据类型(char、byte和short)总是会先转换为int再运算;数据类型大的类型决定了结果的类型 +7.不能仅仅使用返回值不同的方法作为重载方法,应该使参数列表不同(至少是顺序不同) +8.如果已经定义了一个构造器,无论是否有参数,编译器不会自动创建默认构造器 +9.this的三个应用场合: + *用于引用自身对象的成员,特别是因为成员与方法参数重名 + *用于在一个重载的构造器中调用另一个构造器,此时必须放在第一句,且只有构造器可以调用其他构造器 + *用于返回自身对象的引用 +10.被static修饰的方法内不能调用非static方法和成员,因为非static方法和成员依赖具体的对象(除非这个静态方法获得自身类的一个对象实例并通过该实例调用非晶态方法) +11.Java没有C++的析构函数,取而代之是finalize(),用于释放非Java代码(如native C)申请的系统资源,由GC调用(不要直接调用finalize()方法),而GC的调用时机是不能被预期的。 +12.Java的GC机制包括两种:"停止-复制"和“标记-清扫”,都是从堆栈和静态存储区开始扫描引用。采用自适应技术在两种技术中切换,碎片多时用“停止-复制”,碎片少时用“标记-清扫”。 +13.不同于类成员,局部变量必须被初始化,否则报错。 +14.类成员的初始化顺序:类加载->new操作(或访问静态域,此行为不会导致空间分配)->静态成员初始化(包括静态块)(只发生一次,如果以前new操作/访问静态域操作出现过则不再初始化)->分配空间,非静态成员初始化(包括非静态块)->构造方法。类成员变量的初始化(包括但不限于默认初始化行为)绝对先于构造器的对类成员的初始化操作。 + 一个继承自A类的B类对象的初始化顺序:类B加载->类A加载->类A的静态成员初始化->类B的静态成员初始化->类A非静态成员初始化->类A的构造方法->类B非静态成员初始化->类B的构造方法 +15.构造器是static方法。 +16.一下两种声明和初始化数组的方式都是合法的,最后一个逗号是可选的 + *Integer[] a = {new Integer(1), new Integer(2), 3, }//Auto Boxing + *Integer[] b = new Integer[]{new Integer(1), new Integer(2), 3, }//Auto Boxing +17.可变参数形如void function(type... args),三个注意点: + *可以给可变参数列表传0个参数 + *可变参数列表不依赖于Auto Boxing + *尽量避免在多个重载方法中使用可变参数,可能会引起歧义 + void function(int a, int... args){} + void function(int... args){} + *如果必须使用,添加非可变参数如 + void function(int a, int... args){} + void function(string b, int... args){} +18.enum的使用跟类相近,可以使用在switch内。可以对一个enum对象赋予枚举类型值,如EnumType et = EnumType.type1 +19.一个Java源文件中最多只能有一个public类,当有一个public类时,源文件名必须与之一致,否则无法编译,如果源文件中没有一个public类,则文件名与类中没有一致性要求。至于main()不是必须要放在public类中才能运行程序。总结出如下4点 + *Java源文件可以有public类,也可以没有 + *如果有public类,则该public类必须与文件名同名 + *如果没有public类,则不要求有与文件名同名的类 + *main()方法的放在哪个类里没有硬性要求,跟是否在public类中也没有关系,一个文件中多个类可以各自持有一个main()方法,都可以用java命令运行 +20.Java解释器的运行过程是首先找出环境变量CLASSPATH用于查找.class的根目录,然后加载。 +21.访问权限控制的等级:public->protected->包访问权限->private +22.类的权限控制的等级:public->包访问权限,不可以是protected或private的 +23.一个类的构造器是private的,任何其他类无法直接创建该类,只有该类的static方法或对static对象赋值(即非延迟化实现)才可以创建一个该类的对象 +24.使用成员的访问控制主要有两个原因: + *使用户不要碰触他们不该碰触的部分 + *更重要的是,可以让类的设计者改变类的内部实现而不影响会对客户端程序员产生重大影响 +25.使用super可以访问从基类继承的方法和成员,前提是这些方法和成员是public、protected,或着父类和子类在同一个包内且不是private的。 +26.如果父类的构造器没有无参形式(由于用户自定义了带参构造器),子类的构造器需要手动调用super(para);如果存在,则自动调用super(); +27.如果需要保证一个行为一定被执行(例如一些清除操作,手动编写和调用而不应该依赖finalize()和GC),应该将该行为放在finally块中: + try{ + ... + }finally{ + //mustBeDone(); + } + 对于清除操作,如果被清除对象是派生类,则注意对其父类也调用清除操作,方式类似构造方法的构造链的,顺序相反,与C++的析构函数的方式相同。 +28.可以把 @ override放在重写方法之前,如果对父类的方法进行的重载而非重写,编译器会报错 +29.final关键字使用在数据、方法和类的意义不同。 + *final数据: + +对于基本类型,final使数值恒定不变;对于对象引用,final使对象引用不变,而对象本身是可以改变的 + -如数组对象,final int[] a = {1,2,3},a只能指向该数组,但1,2,3是可以修改的 + +static final标识的变量是编译期常量 + -如 final static int a = 1; + +final数据的两次初始化机会:定义处和构造器中。如果在定义处没有初始化,在构造器中必须初始化 + +final参数:在方法内不允许修改该参数变量的值 + *final方法: + +禁止该方法被重写,但可以使用,也即关闭动态绑定 + +在子类中声明一个跟父类private(final)方法同样的方法并不会产生重写效果 + +private方法都隐式的被指定为final方法,private方法并不作为父类接口的一部分,向上转型不能调用子类的同名方法(非覆盖),可能可以调用自身的private方法(如果在父类内部) + *final类:该类不能被继承 +30.多态的三种例外情况: + *private方法。如上所述,private方法被隐式的指定为final方法,因此也不存在重写的情况 + *域。同名的静态域被当成两个不同的数据空间,而不能进行“多态”,根据引用决定调用的目标 + *静态方法。与静态域类似,同名的静态方法会被当成两个不同的方法,没有“多态”,根据引用决定调用的目标 +31.在构造器里调用多态方法可能导致使用了未被正确初始化的变量,如在父类的构造器调用一个在子类中重写的方法,而该方法可能使用了一个子类中的非静态成员变量,该变量此时还未被正确赋值。 +32.Java SE5中添加了协变返回类型,这种机制允许子类重写方法返回父类被重写方法返回类型的派生类型,这样的形式同样被认为是多态的。 +33.包含abstract方法的类必是抽象类,抽象类不一定包含abstract方法(可能出于阻止产生该类对象的目的) +34.Interface的域默认的是static、final和public,方法默认为public。在实现Interface时,必须将实现接口的方法声明为public。接口也可以通过extends关键字来扩展接口 +35.使用Interface的理由 + *为实现多继承提供类似的实现,进而能够向上转型为多个基类型(以及由此带来的灵活性) + *空接口提供一个标签机制 + *多个不同的类型实现同一个接口,可以使得这些类能够向上转型为同一个基类型(例如作为方法的参数来实现策略设计模式,或是作为泛型容器的实现方式) +36.菱形继承问题:在Java中只有一个不合法的情况,即在一个类实现的两个接口中使用了完全一致的静态变量。使用同名函数能够正常工作。 +37.非静态内部类的创建需要捕获一个指向外围类的对象引用,因此不能脱离外围类对象创建内部类对象。内部类对象能访问器外围对象的所有成员,而且不需要任何特殊条件(即使为private),且嵌套层数不影响其对外围对象成员的访问,此外,内部类还拥有器外围类的所有元素的访问权。 +38.创建非静态内部类的两种方法: + *Outer out = new Outer(); + Outer.Inner in = out.createInner(); + *Outer out = new Outer(); + Outer.Inner in = out.new Inner(); + 不能是Outer.Inner in = new Inner();或者Outer.Inner in = out.new Outer.Inner(); +39.静态内部类(嵌套类)不需要对外部类对象的引用 +40.匿名内部类没有构造器,但可以使用非静态块达到实例初始化的目的。如果想在匿名内部类中使用外部方法的变量/参数,则要求这些变量/参数是final的。(传给基类构造器的使用不在此列) +41.匿名内部类只能实现一个接口或者继承一个基类(2选1) +42.为什么需要内部类: From f799dd014991ec8eeb335a0ef43ab799a9e3edda Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 14 Mar 2014 22:44:40 +0800 Subject: [PATCH 223/327] finish but remains typesetting problems --- 13.Java$keywords java.md | 195 +++++++++++++++++++++++++++++++++++---- 1 file changed, 179 insertions(+), 16 deletions(-) diff --git a/13.Java$keywords java.md b/13.Java$keywords java.md index 717deb1..0e88260 100644 --- a/13.Java$keywords java.md +++ b/13.Java$keywords java.md @@ -3,20 +3,28 @@ ###*与C++的一些不同之处 1.char类型的宽度为16bit;c++为8bit 2.没有unsigned修饰符;c++有 -3.下列代码是非法的;c++合法 - int x = 12; +3.下列代码是非法的;c++合法 +```cpp + int x = 12; { int x = 13; - } -4.String s;并没有创建一个对象,只是声明了一个引用;c++在栈上创建了一个对象 -5.类成员会获得默认值;c++不会自动初始化类成员 -6.类成员可以直接初始化;c++的类成员不能直接初始化,可以在构造函数里初始化 -7.对于对象参数,默认为传引用;c++默认为传值 -8.=号赋值只是使新的引用指向了旧的对象,也即新旧引用指向同一个对象;c++则会生成一个新的对象 -9.>>>号是高位补0右移运算符;c++无此符号 -10.拥有finalize()方法;c++只有析构函数 -11.可以使用int[] A或int A[]方式声明一个数组,因为是引用,不可以指定数组大小;c++只能使用int A[]的方式,可以指定数组大小 -12.默认开启动态绑定;C++使用virtual关键字才能开启动态绑定 + } +``` +4.String s;并没有创建一个对象,只是声明了一个引用;c++在栈上创建了一个对象 +5.类成员会获得默认值;c++不会自动初始化类成员 +6.类成员可以直接初始化;c++的类成员不能直接初始化,可以在构造函数里初始化 +7.对于对象参数,默认为传引用;c++默认为传值 +8.=号赋值只是使新的引用指向了旧的对象,也即新旧引用指向同一个对象;c++则会生成一个新的对象 +9.>>>号是高位补0右移运算符;c++无此符号 +10.拥有finalize()方法;c++只有析构函数 +11.可以使用int[] A或int A[]方式声明一个数组,因为是引用,不可以指定数组大小;c++只能使用int A[]的方式,可以指定数组大小 +12.默认开启动态绑定;C++使用virtual关键字才能开启动态绑定 +13.所有容器都有共同的基类Collection;C++容器之间没有共同的基类,依赖迭代器达成共性 +14.泛型和模板对比: + >*C++模板在编译期检查对模板对象的调用是否在该对象所属类总存在来保证类型安全 + >*Java由于采用了类型擦除,仅使用T会使对象所属类被擦除到Object,而非其真正所属类,因此也就无法验证调用是否合法,因此要使用T extends Type来表示泛型边界(一个好的例子见Thinking in Java P375) +15.Comparable接口的方法compareTo(Type obj)返回的值包括-1,0,1,分别表示当前对象小于,等于,大于参数obj; + C++的比较函数cmp(Type obj1, Type obj2)则只返回true和false,obj1<=obj2返回true,反之返回false ###*Java重要知识点 1.java.lang是默认导入每个java文件的 @@ -27,10 +35,10 @@ 6.提升:对基本数据类型进行算术运算或按位运算时,低于int型的数据类型(char、byte和short)总是会先转换为int再运算;数据类型大的类型决定了结果的类型 7.不能仅仅使用返回值不同的方法作为重载方法,应该使参数列表不同(至少是顺序不同) 8.如果已经定义了一个构造器,无论是否有参数,编译器不会自动创建默认构造器 -9.this的三个应用场合: +9.this的三个应用场合: *用于引用自身对象的成员,特别是因为成员与方法参数重名 *用于在一个重载的构造器中调用另一个构造器,此时必须放在第一句,且只有构造器可以调用其他构造器 - *用于返回自身对象的引用 + *用于返回自身对象的引用 10.被static修饰的方法内不能调用非static方法和成员,因为非static方法和成员依赖具体的对象(除非这个静态方法获得自身类的一个对象实例并通过该实例调用非晶态方法) 11.Java没有C++的析构函数,取而代之是finalize(),用于释放非Java代码(如native C)申请的系统资源,由GC调用(不要直接调用finalize()方法),而GC的调用时机是不能被预期的。 12.Java的GC机制包括两种:"停止-复制"和“标记-清扫”,都是从堆栈和静态存储区开始扫描引用。采用自适应技术在两种技术中切换,碎片多时用“停止-复制”,碎片少时用“标记-清扫”。 @@ -49,7 +57,7 @@ void function(int... args){} *如果必须使用,添加非可变参数如 void function(int a, int... args){} - void function(string b, int... args){} + void function(string b, int... args){} 18.enum的使用跟类相近,可以使用在switch内。可以对一个enum对象赋予枚举类型值,如EnumType et = EnumType.type1 19.一个Java源文件中最多只能有一个public类,当有一个public类时,源文件名必须与之一致,否则无法编译,如果源文件中没有一个public类,则文件名与类中没有一致性要求。至于main()不是必须要放在public类中才能运行程序。总结出如下4点 *Java源文件可以有public类,也可以没有 @@ -109,4 +117,159 @@ 39.静态内部类(嵌套类)不需要对外部类对象的引用 40.匿名内部类没有构造器,但可以使用非静态块达到实例初始化的目的。如果想在匿名内部类中使用外部方法的变量/参数,则要求这些变量/参数是final的。(传给基类构造器的使用不在此列) 41.匿名内部类只能实现一个接口或者继承一个基类(2选1) -42.为什么需要内部类: +42.为什么需要内部类:由于内部类可以继承自一个类且可以对外围类进行操作,这意味着多个内部类可以实现更为贴近真正意义上的多重继承,即允许继承多个非接口类型 +43.继承内部类B的派生类A必须提供一个以外部类C作为参数的构造器,并在A的构造器内调用c.super(); +44.通过对容器使用泛型,可以在编译期防止将错误类型对象放入容器中 +45.Object默认的toString()方法=类名+hashcode() +46.List,Set,Map都是实现了Collection接口的容器,其中 + *ArrayList和LinkedList维护插入顺序 + *HashSet维护乱序,TreeSet维护升序,LinkedHashSet维护插入顺序 + *HashMap维护乱序,TreeMap维护升序,LinkedHashMap维护插入顺序 +47.Java的迭代器跟C++类似,主要包括方法: + *collection.iterator();获得当前容器的迭代器,相当于C++的containter.begin(); + *collection.next();获取下一个迭代器位置,相当于C++的itr++; + *collection.hasNext();检查序列中是否还有元素,相当于itr!=container.end(); +48.继承Collection就必须实现iterator()方法,该方法要求返回一个Iterator对象,可以使用匿名内部类方式返回该迭代器对象。 +49.如果想要在foreach中使用某种容器类型(除数组外),要求该容器实现Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,实现iterator()的方法可以参考48。一个好的例子见Thinking in Java P243 +50.使用Arrays.asList()需要谨慎,直接使用该方法返回的容器对象和使用该容器对象构造新的容器对象会产生不同的效果 + *Integer[] ia = {1, 2, 3}; + *List list1 = Array.asList(ia);//对list1的排序会影响ia数组 + *List list2 = new ArrayList(Array.asList(ia));//对list2的排序不会影响底层ia数组 +51.异常处理通常有两种理论模型:终止与恢复。但通常采用终止方法,因为恢复方法需要知道异常抛出地点信息,在大型程序中会增大代码编写和维护的困难。 +52.异常说明(必检异常)形如void f() throws Exception1, Exception2{...},在程序中手动/再次抛出异常使用throw ex1;。声明抛出异常的方法可以不抛出异常,只为占位。异常说明可能有两种意思:一是代码可能产生某些异常需要使用该方法的方法处理,二是代码忽略这些异常,这些异常由方法调用者处理。 +53.异常栈轨迹的栈顶是调用序列的最后一个方法,栈底是调用序列的第一个方法(通常为main())。 +54.如果把当前异常对象重新抛出,则printStackTrace()方法输出的仍然是原来抛出点的的信息,如果对当前异常对象调用fillInStackTrace()方法并抛出其返回的Throwable对象(Exception实现了Throwable接口),则异常栈顶会改写成当前方法。 +55.捕获异常对象后生成一个与之前异常无关的新异常对象,则与fillInStackTrace()效果类似。如果使用旧一场对象构造新异常对象,则构成异常链。 +56.RuntimeException及其任何派生类都属于免检异常,如果在异常的抛出全过程中都没有捕获免检异常的代码,则到达main()程序退出时会调用printStackTrace()。 +57.finally块应用的场合与finalize()不同,用于清理除内存外的其他系统资源占用,如已打开的文件和网络连接等。 +58.需要注意构造器中的异常处理,在处理完之后应该再次抛出以保证不会误导使用者。 +59.在生成需要清理对象阶段应该是try嵌套块来保证对象未生成抛出异常/对象生成了总是能被清理,如 + try{ + // create file + try{ + // do something + }catch(Exception e){ + // exception + }finally{ + // close file operation + } + }catch(Exception e){ + // create file failed + } +60.注意catch块的书写顺序,防止屏蔽现象。 +61.对于多次字符串累加操作,最好使用java.lang.StringBuilder来提高性能。如果需要线程安全特性,使用StringBuffer。 +62.重写toString()要小心无意识递归调用。String类的多数方法在没有改变原对象的情况下会返回原对象引用,改变了则返回新对象的引用。 +63.如果需要格式化输出,System.out.format()和System.out.printf()都可以提供C风格的格式输出,使用String.format()可以用C风格构造一个String对象。%(+-)width.precision type,正负号表示右对齐/左对齐,width表示输出宽度,precision表示输出精度,type表示输出类型。 +64.Java使用Class对象来执行其RTTI,每个.class文件都会有一个对应该类的Class对象,所有的类都是对其第一次使用时动态加载到JVM中的。原生类加载器会首先加载可信类(如Java API类)。当使用一个类时,类加载器首先检查这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件 +65.获取Class对象引用的两种方式:Class.forName()和A.class,前者是Class的静态方法,会触发类的加载;后者是类A的static和final的编译器常量,不会触发类的加载。 +66.可以使用classobj.newInstance()来生成一个新的对象,注意该类必须具有默认构造函数。如果classobj是一个Class对象,则newInstance可以返回一个Type对象,如果classobj是一个Class对象,则返回一个Object对象。 +67.RTTI的另一个种形式是使用instanceof关键字,语法 obj instance classname ,返回值为boolean。instanceof方式检测了所有可能,包括当前类及其派生类,而使用Class对象比较仅检测了当前类是否相等的情况。 +68.反射也必须建立在JVM能够获知当前处理的对象的类型的基础之上,Class与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了、Method已经Constructor类(每个类都实现了Member接口) +69.RTTI和反射之间真正的区别只在于,RTTI是编译器在编译时打开和检查.class,反射是.class在编译时是不可获取,运行时打开和检查文件。 +70.RTTI带来的副作用之一是破坏了API提供者想通过Interface来控制客户端程序员访问权限的机会,客户端程序员可以通过向下转型访问到本不属于接口内的方法,使得这部分的API也成为事实上的公共接口,增大了维护成本。 +71.动态代理:在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是解释调用的类型并确定相应的对策。原理总结: + *代理类和被代理类实现同一个(或多个)接口InterfaceX + *DynamicProxyHandler类实现接口InvocationHandler,并持有一个被代理类的对象,主要通过invoke()方法来联结代理对象和被代理对象 + *java.lang.reflect.Proxy类的newProxyInstance()方法可以动态生成代理对象,该方法的三个参数分别是类加载器,接口列表和Handler对象 + *e.g. InterfaceX proxy = (InterfaceX)Proxy.newProxyInstance(InterfaceX.class.getClassLoader(),new Class[]{InterfaceX.class}, new DynamicProxyHandler(proxied)); +72.泛型类与泛型方法: + *是否是泛型类和是否有泛型方法没有必然联系,但static方法要使用泛型能力必须使自己成为泛型方法 + *使用泛型类时必须显式的指定类型参数,而使用泛型方法则不用,编译器会自动进行参数类型推断 + *泛型类只需要在类名后用<>指定参数类型,泛型方法除了在参数/返回值里使用<>指定参数类型,而且在返回值之前也要用<>指定参数类型 +73.泛型擦除:在泛型代码内部,无法获得任何有关泛型参数类型的信息,在使用泛型时任何具体类型信息都被擦除,List和List在运行时事实上是相同的类型,都被擦除成相同类型List,尽管如此,编译器可以确保方法或类中使用的类型的内部一致性。 + *Class c1 = new ArrayList().getClass(); + *Class c2 = new ArrayList().getClass(); + *c1 == c2 为 true +74.无法在对泛型进行的操作:instanceof,new,转型(将T转型为其他类型),因为类型擦除导致类型信息丢失,但可以使用Class对象用newInstance()方法创建对象。创建数组可以通过 T[] array = (T[])new Object[size];进行,切记array在运行时类型只能是Object[] +75.Arrays使用方法,equals()比较相等,fill()填充,sort()排序,binarySearch()在排序数组中查找,toString(),hashcode()。此外还有System.arraycopy(),这种拷贝方式比用for快很多。 +76.通过实现java.lang.Comparable接口可以让容器和数组的sort()对自定义类进行排序,需要实现campareTo()方法 +77.Object使用对象的地址作为hashcode()和equals ()的默认实现。如果要使用自己的类作为HashMap的键,必须同时重载hashCode()和equals()方法。 +78.equals()决定了在链式冲突中寻找唯一对象的标准。equals()的重载方法 + public boolean equals(Object o){ + return o instance of Type && (member1 == ((Type)o).member1)&&..&&(memberk == ((Type)o).memberk) + } +79.hashcode()的重载方法 + public int hashCode(){ + int result = 17; + result = result * 37 + member1.hashCode(); + result = result * 37 + c(member2); + result = result * 37 + c(memberk); + } + 其中c()是对基本类型的整数化操作。 +85.File类不仅仅指单一文件名称,也可能是一个文件集合 +86.System.out和System.err已经被包装成PrintStream对象,因此可以直接输出,但System.in还是原始的InputStream,因此需要输入包装类才能使其正常工作,如BufferReader in = new BufferReader(new InputStreamReader(System.in)); +87.System.setIn(InputStream), System.setOut(PrintStream)和System.setErr(PrintStream)可以重定向标准输入/输出流 +88.对于文件流对象,可以调用FileLock fl = ((FileOuputStream)fos).getChannel().tryLock();注意tryLock()是非阻塞方法,而lock()是阻塞方法,release()可以释放锁。 +89. 一般的序列化需求就实现Serializable接口,如果是需要自己控制序列化过程则实现Externalizable接口。transient关键字可以用于不想被序列化的类成员之前防止被序列化。 +90.Java的线程机制是抢占式的(但协作式有着更小的代价)。实现一个线程类 + public class A implements Runnable{ + // Constructer omit + public void run(){ + // Do something + Thread.yeild();//通知线程调度器自己任务已经完成(可选) + } + } +但是一个实现Runnable接口的类并不具有产生线程的能力,要实现线程行为,必须显式地将一个任务附在线程上。具体做法是使用Runnable对象作为参数生成一个Tread对象,再调用Thread对象的start()方法,该方法是一个非阻塞方法,启动线程后立即返回。如果直接调用Runnable的run()方法,则会阻塞调用线程(如main线程)。 +91.Java提供线程池ExecutorService类,创建一个线程池的代码如下 + ExecutorService exec1 = Executors.newCachedTreadPool();//创建一个大小可变的线程池,合理的首选 + ExecutorService exec2 = Executors.newFixedTreadPool(5);//创建一个固定大小的线程池,一次性执行线程分配,效率高 + ExecutorService exec3 = Executors.newSingleTreadPool();//创建大小为1的线程池,可以提交多个线程,但线程会排队,用于socket监听类任务 + 提交线程任务 + exec1.execute(new A());//A是90中提到的Runnable实现类 + 阻止一个线程池继续工作的方法 + exec1.shutdown();//无法继续提交新的线程任务,旧的会继续执行完毕 +92.通过Tread.currentThread()可以获得当前执行线程的对象引用。JDK有10个进程优先级,而Windows有7个优先级且不是固定的。 +93.线程分为后台线程和非后台线程,后台线程往往是提供通用服务的线程,不属于不可获取的部分,非后台线程反之,如main线程。当所有非后台线程结束工作时,程序终止,后台线程会立即被终止,即使finally也不能得到保证(非后台线程的finally一定会执行)。 +94.通过把方法标记为synchronized来防止资源冲突,如方法f()和g()都会对某个关键资源操作,则加上synchronized关键字 + synchronized void f(){} + synchronized void g(){} +所有对象都含有单一的锁,对于某个特定的对象,所有的synchronized方法共享一个锁,事实上等同synchronized(this),一个synchronized方法被调用,其他线程便不能调用其他synchronized方法。在使用并发时,将域设置为private非常重要,否则synchronized关键字不能防止其他任务直接访问域,进而产生冲突。 +95.JVM负责跟踪对象的加锁次数,一个任务可以多次获得对象的锁。如果一个方法又调用了自身的一个同步方法,则加速次数加1,一个对象被解锁当且仅当其加锁计数减为0。针对每个类也有一个锁,对static方法适用synchronized关键字可以防止静态方法冲突。 +96.可以使用synchronized(otherObject)来实现互斥,但要保证所有使用同一个关键资源的代码块在同一个对象上加锁。 +97.使用java.util.concurrent.locks类实现互斥,相比使用synchronized关键字能够实现更加灵活,粒度更细的加锁 + Lock lock = new ReentrantLock(); + lock.lock(); + try{ + // Do something + return; + }finally{ + lock.unlock(); + } +98.volatile关键字可以让域得到立即更新,因而同步性得到一定保障,如果一个域完全被synchronized包括,则不必使用volatile。 +99.线程状态: + *新建(new):已被分配资源且初始化,等待调度 + *就绪(runnable):只要调度就可运行 + *阻塞(blocked):因某个条件被阻止运行,调度器忽略此线程 + *死亡(dead):不可运行 +100.造成阻塞的原因包括 + *sleep()休眠,可以中断 + *wait()挂起,等待notify()或notifyAll()方法,在挂起期间锁会被释放 + *等待IO,不可中断 + *试图获得锁但未成功,不可中断 +101.向持有某对象锁的所有线程发送通知 + synchronized(x){ + x.notifyAll();//所有等待线程竞争该锁 + //x.notify; 仅通知单一线程来获取该锁 + } +102.生产者消费者代码示例见Thinking in java P709 +103.如果使用BlockingQueue和PriorityBlockingQueue可以直接使用put()和take()方法而不同担心手动同步问题,容器已经在内部同步。 +104.产生死锁的四个必要条件 + *互斥条件,即使用的资源中至少有一个不能共享 + *等待,即至少有一个线程掌握一部分资源的同时等待另外一些资源 + *资源不能被抢占,即只能等待别人释放 + *循环等待 +只需要破坏一个即可阻止死锁 +105.正常的锁(来自concurrent.locks或内建的synchronized锁)在任何时刻都只允许一个任务访问一项资源,而Semaphore则允许n个线程同时访问这个资源 + Semaphore sem = new Semaphore(size, true); + sem.acquire(); + sem.release(); +106.线程相对与进程更加轻量级,切换仅需要100条左右的指令,而进程需要上千条,同时进程需要切换上下文,而线程只需要改变程序的执行序列和局部变量。 +107.线程的缺陷: + *等待临界资源时效率降低 + *处理线程带来的额外CPU开销 + *增加了程序的复杂度 + *有可能产生病态行为,如饿死,竞争,死锁,活锁(多个线程各自运行导致无法完成整体任务)等 + *平台不一致性 + +注:由于时间原因和过于复杂的内容跳过泛型一章P389页之后的内容、枚举类型一章,注解一章的内容,以后补完。 + From 5872b50afa935e5ec25539fc0058da5a36c1ee81 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 14 Mar 2014 22:50:30 +0800 Subject: [PATCH 224/327] rearrange --- 13.Java$keywords java.md | 308 +++++++++++++++++++-------------------- 1 file changed, 154 insertions(+), 154 deletions(-) diff --git a/13.Java$keywords java.md b/13.Java$keywords java.md index 0e88260..194cc69 100644 --- a/13.Java$keywords java.md +++ b/13.Java$keywords java.md @@ -117,159 +117,159 @@ 39.静态内部类(嵌套类)不需要对外部类对象的引用 40.匿名内部类没有构造器,但可以使用非静态块达到实例初始化的目的。如果想在匿名内部类中使用外部方法的变量/参数,则要求这些变量/参数是final的。(传给基类构造器的使用不在此列) 41.匿名内部类只能实现一个接口或者继承一个基类(2选1) -42.为什么需要内部类:由于内部类可以继承自一个类且可以对外围类进行操作,这意味着多个内部类可以实现更为贴近真正意义上的多重继承,即允许继承多个非接口类型 -43.继承内部类B的派生类A必须提供一个以外部类C作为参数的构造器,并在A的构造器内调用c.super(); -44.通过对容器使用泛型,可以在编译期防止将错误类型对象放入容器中 -45.Object默认的toString()方法=类名+hashcode() -46.List,Set,Map都是实现了Collection接口的容器,其中 - *ArrayList和LinkedList维护插入顺序 - *HashSet维护乱序,TreeSet维护升序,LinkedHashSet维护插入顺序 - *HashMap维护乱序,TreeMap维护升序,LinkedHashMap维护插入顺序 -47.Java的迭代器跟C++类似,主要包括方法: - *collection.iterator();获得当前容器的迭代器,相当于C++的containter.begin(); - *collection.next();获取下一个迭代器位置,相当于C++的itr++; - *collection.hasNext();检查序列中是否还有元素,相当于itr!=container.end(); -48.继承Collection就必须实现iterator()方法,该方法要求返回一个Iterator对象,可以使用匿名内部类方式返回该迭代器对象。 -49.如果想要在foreach中使用某种容器类型(除数组外),要求该容器实现Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,实现iterator()的方法可以参考48。一个好的例子见Thinking in Java P243 -50.使用Arrays.asList()需要谨慎,直接使用该方法返回的容器对象和使用该容器对象构造新的容器对象会产生不同的效果 - *Integer[] ia = {1, 2, 3}; - *List list1 = Array.asList(ia);//对list1的排序会影响ia数组 - *List list2 = new ArrayList(Array.asList(ia));//对list2的排序不会影响底层ia数组 -51.异常处理通常有两种理论模型:终止与恢复。但通常采用终止方法,因为恢复方法需要知道异常抛出地点信息,在大型程序中会增大代码编写和维护的困难。 -52.异常说明(必检异常)形如void f() throws Exception1, Exception2{...},在程序中手动/再次抛出异常使用throw ex1;。声明抛出异常的方法可以不抛出异常,只为占位。异常说明可能有两种意思:一是代码可能产生某些异常需要使用该方法的方法处理,二是代码忽略这些异常,这些异常由方法调用者处理。 -53.异常栈轨迹的栈顶是调用序列的最后一个方法,栈底是调用序列的第一个方法(通常为main())。 -54.如果把当前异常对象重新抛出,则printStackTrace()方法输出的仍然是原来抛出点的的信息,如果对当前异常对象调用fillInStackTrace()方法并抛出其返回的Throwable对象(Exception实现了Throwable接口),则异常栈顶会改写成当前方法。 -55.捕获异常对象后生成一个与之前异常无关的新异常对象,则与fillInStackTrace()效果类似。如果使用旧一场对象构造新异常对象,则构成异常链。 -56.RuntimeException及其任何派生类都属于免检异常,如果在异常的抛出全过程中都没有捕获免检异常的代码,则到达main()程序退出时会调用printStackTrace()。 -57.finally块应用的场合与finalize()不同,用于清理除内存外的其他系统资源占用,如已打开的文件和网络连接等。 -58.需要注意构造器中的异常处理,在处理完之后应该再次抛出以保证不会误导使用者。 -59.在生成需要清理对象阶段应该是try嵌套块来保证对象未生成抛出异常/对象生成了总是能被清理,如 - try{ - // create file - try{ - // do something - }catch(Exception e){ - // exception - }finally{ - // close file operation - } - }catch(Exception e){ - // create file failed - } -60.注意catch块的书写顺序,防止屏蔽现象。 -61.对于多次字符串累加操作,最好使用java.lang.StringBuilder来提高性能。如果需要线程安全特性,使用StringBuffer。 -62.重写toString()要小心无意识递归调用。String类的多数方法在没有改变原对象的情况下会返回原对象引用,改变了则返回新对象的引用。 -63.如果需要格式化输出,System.out.format()和System.out.printf()都可以提供C风格的格式输出,使用String.format()可以用C风格构造一个String对象。%(+-)width.precision type,正负号表示右对齐/左对齐,width表示输出宽度,precision表示输出精度,type表示输出类型。 -64.Java使用Class对象来执行其RTTI,每个.class文件都会有一个对应该类的Class对象,所有的类都是对其第一次使用时动态加载到JVM中的。原生类加载器会首先加载可信类(如Java API类)。当使用一个类时,类加载器首先检查这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件 -65.获取Class对象引用的两种方式:Class.forName()和A.class,前者是Class的静态方法,会触发类的加载;后者是类A的static和final的编译器常量,不会触发类的加载。 -66.可以使用classobj.newInstance()来生成一个新的对象,注意该类必须具有默认构造函数。如果classobj是一个Class对象,则newInstance可以返回一个Type对象,如果classobj是一个Class对象,则返回一个Object对象。 -67.RTTI的另一个种形式是使用instanceof关键字,语法 obj instance classname ,返回值为boolean。instanceof方式检测了所有可能,包括当前类及其派生类,而使用Class对象比较仅检测了当前类是否相等的情况。 -68.反射也必须建立在JVM能够获知当前处理的对象的类型的基础之上,Class与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了、Method已经Constructor类(每个类都实现了Member接口) -69.RTTI和反射之间真正的区别只在于,RTTI是编译器在编译时打开和检查.class,反射是.class在编译时是不可获取,运行时打开和检查文件。 -70.RTTI带来的副作用之一是破坏了API提供者想通过Interface来控制客户端程序员访问权限的机会,客户端程序员可以通过向下转型访问到本不属于接口内的方法,使得这部分的API也成为事实上的公共接口,增大了维护成本。 -71.动态代理:在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是解释调用的类型并确定相应的对策。原理总结: - *代理类和被代理类实现同一个(或多个)接口InterfaceX - *DynamicProxyHandler类实现接口InvocationHandler,并持有一个被代理类的对象,主要通过invoke()方法来联结代理对象和被代理对象 - *java.lang.reflect.Proxy类的newProxyInstance()方法可以动态生成代理对象,该方法的三个参数分别是类加载器,接口列表和Handler对象 - *e.g. InterfaceX proxy = (InterfaceX)Proxy.newProxyInstance(InterfaceX.class.getClassLoader(),new Class[]{InterfaceX.class}, new DynamicProxyHandler(proxied)); -72.泛型类与泛型方法: - *是否是泛型类和是否有泛型方法没有必然联系,但static方法要使用泛型能力必须使自己成为泛型方法 - *使用泛型类时必须显式的指定类型参数,而使用泛型方法则不用,编译器会自动进行参数类型推断 - *泛型类只需要在类名后用<>指定参数类型,泛型方法除了在参数/返回值里使用<>指定参数类型,而且在返回值之前也要用<>指定参数类型 -73.泛型擦除:在泛型代码内部,无法获得任何有关泛型参数类型的信息,在使用泛型时任何具体类型信息都被擦除,List和List在运行时事实上是相同的类型,都被擦除成相同类型List,尽管如此,编译器可以确保方法或类中使用的类型的内部一致性。 - *Class c1 = new ArrayList().getClass(); - *Class c2 = new ArrayList().getClass(); - *c1 == c2 为 true -74.无法在对泛型进行的操作:instanceof,new,转型(将T转型为其他类型),因为类型擦除导致类型信息丢失,但可以使用Class对象用newInstance()方法创建对象。创建数组可以通过 T[] array = (T[])new Object[size];进行,切记array在运行时类型只能是Object[] -75.Arrays使用方法,equals()比较相等,fill()填充,sort()排序,binarySearch()在排序数组中查找,toString(),hashcode()。此外还有System.arraycopy(),这种拷贝方式比用for快很多。 -76.通过实现java.lang.Comparable接口可以让容器和数组的sort()对自定义类进行排序,需要实现campareTo()方法 -77.Object使用对象的地址作为hashcode()和equals ()的默认实现。如果要使用自己的类作为HashMap的键,必须同时重载hashCode()和equals()方法。 -78.equals()决定了在链式冲突中寻找唯一对象的标准。equals()的重载方法 - public boolean equals(Object o){ - return o instance of Type && (member1 == ((Type)o).member1)&&..&&(memberk == ((Type)o).memberk) - } -79.hashcode()的重载方法 - public int hashCode(){ - int result = 17; - result = result * 37 + member1.hashCode(); - result = result * 37 + c(member2); - result = result * 37 + c(memberk); - } - 其中c()是对基本类型的整数化操作。 -85.File类不仅仅指单一文件名称,也可能是一个文件集合 -86.System.out和System.err已经被包装成PrintStream对象,因此可以直接输出,但System.in还是原始的InputStream,因此需要输入包装类才能使其正常工作,如BufferReader in = new BufferReader(new InputStreamReader(System.in)); -87.System.setIn(InputStream), System.setOut(PrintStream)和System.setErr(PrintStream)可以重定向标准输入/输出流 -88.对于文件流对象,可以调用FileLock fl = ((FileOuputStream)fos).getChannel().tryLock();注意tryLock()是非阻塞方法,而lock()是阻塞方法,release()可以释放锁。 -89. 一般的序列化需求就实现Serializable接口,如果是需要自己控制序列化过程则实现Externalizable接口。transient关键字可以用于不想被序列化的类成员之前防止被序列化。 -90.Java的线程机制是抢占式的(但协作式有着更小的代价)。实现一个线程类 - public class A implements Runnable{ - // Constructer omit - public void run(){ - // Do something - Thread.yeild();//通知线程调度器自己任务已经完成(可选) - } - } -但是一个实现Runnable接口的类并不具有产生线程的能力,要实现线程行为,必须显式地将一个任务附在线程上。具体做法是使用Runnable对象作为参数生成一个Tread对象,再调用Thread对象的start()方法,该方法是一个非阻塞方法,启动线程后立即返回。如果直接调用Runnable的run()方法,则会阻塞调用线程(如main线程)。 -91.Java提供线程池ExecutorService类,创建一个线程池的代码如下 - ExecutorService exec1 = Executors.newCachedTreadPool();//创建一个大小可变的线程池,合理的首选 - ExecutorService exec2 = Executors.newFixedTreadPool(5);//创建一个固定大小的线程池,一次性执行线程分配,效率高 - ExecutorService exec3 = Executors.newSingleTreadPool();//创建大小为1的线程池,可以提交多个线程,但线程会排队,用于socket监听类任务 - 提交线程任务 - exec1.execute(new A());//A是90中提到的Runnable实现类 - 阻止一个线程池继续工作的方法 - exec1.shutdown();//无法继续提交新的线程任务,旧的会继续执行完毕 -92.通过Tread.currentThread()可以获得当前执行线程的对象引用。JDK有10个进程优先级,而Windows有7个优先级且不是固定的。 -93.线程分为后台线程和非后台线程,后台线程往往是提供通用服务的线程,不属于不可获取的部分,非后台线程反之,如main线程。当所有非后台线程结束工作时,程序终止,后台线程会立即被终止,即使finally也不能得到保证(非后台线程的finally一定会执行)。 -94.通过把方法标记为synchronized来防止资源冲突,如方法f()和g()都会对某个关键资源操作,则加上synchronized关键字 - synchronized void f(){} - synchronized void g(){} -所有对象都含有单一的锁,对于某个特定的对象,所有的synchronized方法共享一个锁,事实上等同synchronized(this),一个synchronized方法被调用,其他线程便不能调用其他synchronized方法。在使用并发时,将域设置为private非常重要,否则synchronized关键字不能防止其他任务直接访问域,进而产生冲突。 -95.JVM负责跟踪对象的加锁次数,一个任务可以多次获得对象的锁。如果一个方法又调用了自身的一个同步方法,则加速次数加1,一个对象被解锁当且仅当其加锁计数减为0。针对每个类也有一个锁,对static方法适用synchronized关键字可以防止静态方法冲突。 -96.可以使用synchronized(otherObject)来实现互斥,但要保证所有使用同一个关键资源的代码块在同一个对象上加锁。 -97.使用java.util.concurrent.locks类实现互斥,相比使用synchronized关键字能够实现更加灵活,粒度更细的加锁 - Lock lock = new ReentrantLock(); - lock.lock(); - try{ - // Do something - return; - }finally{ - lock.unlock(); - } -98.volatile关键字可以让域得到立即更新,因而同步性得到一定保障,如果一个域完全被synchronized包括,则不必使用volatile。 -99.线程状态: - *新建(new):已被分配资源且初始化,等待调度 - *就绪(runnable):只要调度就可运行 - *阻塞(blocked):因某个条件被阻止运行,调度器忽略此线程 - *死亡(dead):不可运行 -100.造成阻塞的原因包括 - *sleep()休眠,可以中断 - *wait()挂起,等待notify()或notifyAll()方法,在挂起期间锁会被释放 - *等待IO,不可中断 - *试图获得锁但未成功,不可中断 -101.向持有某对象锁的所有线程发送通知 - synchronized(x){ - x.notifyAll();//所有等待线程竞争该锁 - //x.notify; 仅通知单一线程来获取该锁 - } -102.生产者消费者代码示例见Thinking in java P709 -103.如果使用BlockingQueue和PriorityBlockingQueue可以直接使用put()和take()方法而不同担心手动同步问题,容器已经在内部同步。 -104.产生死锁的四个必要条件 - *互斥条件,即使用的资源中至少有一个不能共享 - *等待,即至少有一个线程掌握一部分资源的同时等待另外一些资源 - *资源不能被抢占,即只能等待别人释放 - *循环等待 -只需要破坏一个即可阻止死锁 -105.正常的锁(来自concurrent.locks或内建的synchronized锁)在任何时刻都只允许一个任务访问一项资源,而Semaphore则允许n个线程同时访问这个资源 - Semaphore sem = new Semaphore(size, true); - sem.acquire(); - sem.release(); -106.线程相对与进程更加轻量级,切换仅需要100条左右的指令,而进程需要上千条,同时进程需要切换上下文,而线程只需要改变程序的执行序列和局部变量。 -107.线程的缺陷: - *等待临界资源时效率降低 - *处理线程带来的额外CPU开销 - *增加了程序的复杂度 - *有可能产生病态行为,如饿死,竞争,死锁,活锁(多个线程各自运行导致无法完成整体任务)等 - *平台不一致性 +42.为什么需要内部类:由于内部类可以继承自一个类且可以对外围类进行操作,这意味着多个内部类可以实现更为贴近真正意义上的多重继承,即允许继承多个非接口类型 +43.继承内部类B的派生类A必须提供一个以外部类C作为参数的构造器,并在A的构造器内调用c.super(); +44.通过对容器使用泛型,可以在编译期防止将错误类型对象放入容器中 +45.Object默认的toString()方法=类名+hashcode() +46.List,Set,Map都是实现了Collection接口的容器,其中 + *ArrayList和LinkedList维护插入顺序 + *HashSet维护乱序,TreeSet维护升序,LinkedHashSet维护插入顺序 + *HashMap维护乱序,TreeMap维护升序,LinkedHashMap维护插入顺序 +47.Java的迭代器跟C++类似,主要包括方法: + *collection.iterator();获得当前容器的迭代器,相当于C++的containter.begin(); + *collection.next();获取下一个迭代器位置,相当于C++的itr++; + *collection.hasNext();检查序列中是否还有元素,相当于itr!=container.end(); +48.继承Collection就必须实现iterator()方法,该方法要求返回一个Iterator对象,可以使用匿名内部类方式返回该迭代器对象。 +49.如果想要在foreach中使用某种容器类型(除数组外),要求该容器实现Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,实现iterator()的方法可以参考48。一个好的例子见Thinking in Java P243 +50.使用Arrays.asList()需要谨慎,直接使用该方法返回的容器对象和使用该容器对象构造新的容器对象会产生不同的效果 + *Integer[] ia = {1, 2, 3}; + *List list1 = Array.asList(ia);//对list1的排序会影响ia数组 + *List list2 = new ArrayList(Array.asList(ia));//对list2的排序不会影响底层ia数组 +51.异常处理通常有两种理论模型:终止与恢复。但通常采用终止方法,因为恢复方法需要知道异常抛出地点信息,在大型程序中会增大代码编写和维护的困难。 +52.异常说明(必检异常)形如void f() throws Exception1, Exception2{...},在程序中手动/再次抛出异常使用throw ex1;。声明抛出异常的方法可以不抛出异常,只为占位。异常说明可能有两种意思:一是代码可能产生某些异常需要使用该方法的方法处理,二是代码忽略这些异常,这些异常由方法调用者处理。 +53.异常栈轨迹的栈顶是调用序列的最后一个方法,栈底是调用序列的第一个方法(通常为main())。 +54.如果把当前异常对象重新抛出,则printStackTrace()方法输出的仍然是原来抛出点的的信息,如果对当前异常对象调用fillInStackTrace()方法并抛出其返回的Throwable对象(Exception实现了Throwable接口),则异常栈顶会改写成当前方法。 +55.捕获异常对象后生成一个与之前异常无关的新异常对象,则与fillInStackTrace()效果类似。如果使用旧一场对象构造新异常对象,则构成异常链。 +56.RuntimeException及其任何派生类都属于免检异常,如果在异常的抛出全过程中都没有捕获免检异常的代码,则到达main()程序退出时会调用printStackTrace()。 +57.finally块应用的场合与finalize()不同,用于清理除内存外的其他系统资源占用,如已打开的文件和网络连接等。 +58.需要注意构造器中的异常处理,在处理完之后应该再次抛出以保证不会误导使用者。 +59.在生成需要清理对象阶段应该是try嵌套块来保证对象未生成抛出异常/对象生成了总是能被清理,如 + try{ + // create file + try{ + // do something + }catch(Exception e){ + // exception + }finally{ + // close file operation + } + }catch(Exception e){ + // create file failed + } +60.注意catch块的书写顺序,防止屏蔽现象。 +61.对于多次字符串累加操作,最好使用java.lang.StringBuilder来提高性能。如果需要线程安全特性,使用StringBuffer。 +62.重写toString()要小心无意识递归调用。String类的多数方法在没有改变原对象的情况下会返回原对象引用,改变了则返回新对象的引用。 +63.如果需要格式化输出,System.out.format()和System.out.printf()都可以提供C风格的格式输出,使用String.format()可以用C风格构造一个String对象。%(+-)width.precision type,正负号表示右对齐/左对齐,width表示输出宽度,precision表示输出精度,type表示输出类型。 +64.Java使用Class对象来执行其RTTI,每个.class文件都会有一个对应该类的Class对象,所有的类都是对其第一次使用时动态加载到JVM中的。原生类加载器会首先加载可信类(如Java API类)。当使用一个类时,类加载器首先检查这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件 +65.获取Class对象引用的两种方式:Class.forName()和A.class,前者是Class的静态方法,会触发类的加载;后者是类A的static和final的编译器常量,不会触发类的加载。 +66.可以使用classobj.newInstance()来生成一个新的对象,注意该类必须具有默认构造函数。如果classobj是一个Class对象,则newInstance可以返回一个Type对象,如果classobj是一个Class对象,则返回一个Object对象。 +67.RTTI的另一个种形式是使用instanceof关键字,语法 obj instance classname ,返回值为boolean。instanceof方式检测了所有可能,包括当前类及其派生类,而使用Class对象比较仅检测了当前类是否相等的情况。 +68.反射也必须建立在JVM能够获知当前处理的对象的类型的基础之上,Class与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了、Method已经Constructor类(每个类都实现了Member接口) +69.RTTI和反射之间真正的区别只在于,RTTI是编译器在编译时打开和检查.class,反射是.class在编译时是不可获取,运行时打开和检查文件。 +70.RTTI带来的副作用之一是破坏了API提供者想通过Interface来控制客户端程序员访问权限的机会,客户端程序员可以通过向下转型访问到本不属于接口内的方法,使得这部分的API也成为事实上的公共接口,增大了维护成本。 +71.动态代理:在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是解释调用的类型并确定相应的对策。原理总结: + *代理类和被代理类实现同一个(或多个)接口InterfaceX + *DynamicProxyHandler类实现接口InvocationHandler,并持有一个被代理类的对象,主要通过invoke()方法来联结代理对象和被代理对象 + *java.lang.reflect.Proxy类的newProxyInstance()方法可以动态生成代理对象,该方法的三个参数分别是类加载器,接口列表和Handler对象 + *e.g. InterfaceX proxy = (InterfaceX)Proxy.newProxyInstance(InterfaceX.class.getClassLoader(),new Class[] {InterfaceX.class}, new DynamicProxyHandler(proxied)); +72.泛型类与泛型方法: + *是否是泛型类和是否有泛型方法没有必然联系,但static方法要使用泛型能力必须使自己成为泛型方法 + *使用泛型类时必须显式的指定类型参数,而使用泛型方法则不用,编译器会自动进行参数类型推断 + *泛型类只需要在类名后用<>指定参数类型,泛型方法除了在参数/返回值里使用<>指定参数类型,而且在返回值之前也要用<>指定参数类型 +73.泛型擦除:在泛型代码内部,无法获得任何有关泛型参数类型的信息,在使用泛型时任何具体类型信息都被擦除,List和List在运行时事实上是相同的类型,都被擦除成相同类型List,尽管如此,编译器可以确保方法或类中使用的类型的内部一致性。 + *Class c1 = new ArrayList().getClass(); + *Class c2 = new ArrayList().getClass(); + *c1 == c2 为 true +74.无法在对泛型进行的操作:instanceof,new,转型(将T转型为其他类型),因为类型擦除导致类型信息丢失,但可以使用Class对象用newInstance()方法创建对象。创建数组可以通过 T[] array = (T[])new Object[size];进行,切记array在运行时类型只能是Object[] +75.Arrays使用方法,equals()比较相等,fill()填充,sort()排序,binarySearch()在排序数组中查找,toString(),hashcode()。此外还有System.arraycopy(),这种拷贝方式比用for快很多。 +76.通过实现java.lang.Comparable接口可以让容器和数组的sort()对自定义类进行排序,需要实现campareTo()方法 +77.Object使用对象的地址作为hashcode()和equals ()的默认实现。如果要使用自己的类作为HashMap的键,必须同时重载hashCode()和equals()方法。 +78.equals()决定了在链式冲突中寻找唯一对象的标准。equals()的重载方法 + public boolean equals(Object o){ + return o instance of Type && (member1 == ((Type)o).member1)&&..&&(memberk == ((Type)o).memberk) + } +79.hashcode()的重载方法 + public int hashCode(){ + int result = 17; + result = result * 37 + member1.hashCode(); + result = result * 37 + c(member2); + result = result * 37 + c(memberk); + } + 其中c()是对基本类型的整数化操作。 +85.File类不仅仅指单一文件名称,也可能是一个文件集合 +86.System.out和System.err已经被包装成PrintStream对象,因此可以直接输出,但System.in还是原始的InputStream,因此需要输入包装类才能使其正常工作,如BufferReader in = new BufferReader(new InputStreamReader(System.in)); +87.System.setIn(InputStream), System.setOut(PrintStream)和System.setErr(PrintStream)可以重定向标准输入/输出流 +88.对于文件流对象,可以调用FileLock fl = ((FileOuputStream)fos).getChannel().tryLock();注意tryLock()是非阻塞方法,而lock()是阻塞方法,release()可以释放锁。 +89. 一般的序列化需求就实现Serializable接口,如果是需要自己控制序列化过程则实现Externalizable接口。transient关键字可以用于不想被序列化的类成员之前防止被序列化。 +90.Java的线程机制是抢占式的(但协作式有着更小的代价)。实现一个线程类 + public class A implements Runnable{ + // Constructer omit + public void run(){ + // Do something + Thread.yeild();//通知线程调度器自己任务已经完成(可选) + } + } +但是一个实现Runnable接口的类并不具有产生线程的能力,要实现线程行为,必须显式地将一个任务附在线程上。具体做法是使用Runnable对象作为参数生成一个Tread对象,再调用Thread对象的start()方法,该方法是一个非阻塞方法,启动线程后立即返回。如果直接调用Runnable的run()方法,则会阻塞调用线程(如main线程)。 +91.Java提供线程池ExecutorService类,创建一个线程池的代码如下 + ExecutorService exec1 = Executors.newCachedTreadPool();//创建一个大小可变的线程池,合理的首选 + ExecutorService exec2 = Executors.newFixedTreadPool(5);//创建一个固定大小的线程池,一次性执行线程分配,效率高 + ExecutorService exec3 = Executors.newSingleTreadPool();//创建大小为1的线程池,可以提交多个线程,但线程会排队,用于socket监听类任务 + 提交线程任务 + exec1.execute(new A());//A是90中提到的Runnable实现类 + 阻止一个线程池继续工作的方法 + exec1.shutdown();//无法继续提交新的线程任务,旧的会继续执行完毕 +92.通过Tread.currentThread()可以获得当前执行线程的对象引用。JDK有10个进程优先级,而Windows有7个优先级且不是固定的。 +93.线程分为后台线程和非后台线程,后台线程往往是提供通用服务的线程,不属于不可获取的部分,非后台线程反之,如main线程。当所有非后台线程结束工作时,程序终止,后台线程会立即被终止,即使finally也不能得到保证(非后台线程的finally一定会执行)。 +94.通过把方法标记为synchronized来防止资源冲突,如方法f()和g()都会对某个关键资源操作,则加上synchronized关键字 + synchronized void f(){} + synchronized void g(){} +所有对象都含有单一的锁,对于某个特定的对象,所有的synchronized方法共享一个锁,事实上等同synchronized(this),一个synchronized方法被调用,其他线程便不能调用其他synchronized方法。在使用并发时,将域设置为private非常重要,否则synchronized关键字不能防止其他任务直接访问域,进而产生冲突。 +95.JVM负责跟踪对象的加锁次数,一个任务可以多次获得对象的锁。如果一个方法又调用了自身的一个同步方法,则加速次数加1,一个对象被解锁当且仅当其加锁计数减为0。针对每个类也有一个锁,对static方法适用synchronized关键字可以防止静态方法冲突。 +96.可以使用synchronized(otherObject)来实现互斥,但要保证所有使用同一个关键资源的代码块在同一个对象上加锁。 +97.使用java.util.concurrent.locks类实现互斥,相比使用synchronized关键字能够实现更加灵活,粒度更细的加锁 + Lock lock = new ReentrantLock(); + lock.lock(); + try{ + // Do something + return; + }finally{ + lock.unlock(); + } +98.volatile关键字可以让域得到立即更新,因而同步性得到一定保障,如果一个域完全被synchronized包括,则不必使用volatile。 +99.线程状态: + *新建(new):已被分配资源且初始化,等待调度 + *就绪(runnable):只要调度就可运行 + *阻塞(blocked):因某个条件被阻止运行,调度器忽略此线程 + *死亡(dead):不可运行 +100.造成阻塞的原因包括 + *sleep()休眠,可以中断 + *wait()挂起,等待notify()或notifyAll()方法,在挂起期间锁会被释放 + *等待IO,不可中断 + *试图获得锁但未成功,不可中断 +101.向持有某对象锁的所有线程发送通知 + synchronized(x){ + x.notifyAll();//所有等待线程竞争该锁 + //x.notify; 仅通知单一线程来获取该锁 + } +102.生产者消费者代码示例见Thinking in java P709 +103.如果使用BlockingQueue和PriorityBlockingQueue可以直接使用put()和take()方法而不同担心手动同步问题,容器已经在内部同步。 +104.产生死锁的四个必要条件 + *互斥条件,即使用的资源中至少有一个不能共享 + *等待,即至少有一个线程掌握一部分资源的同时等待另外一些资源 + *资源不能被抢占,即只能等待别人释放 + *循环等待 +只需要破坏一个即可阻止死锁 +105.正常的锁(来自concurrent.locks或内建的synchronized锁)在任何时刻都只允许一个任务访问一项资源,而Semaphore则允许n个线程同时访问这个资源 + Semaphore sem = new Semaphore(size, true); + sem.acquire(); + sem.release(); +106.线程相对与进程更加轻量级,切换仅需要100条左右的指令,而进程需要上千条,同时进程需要切换上下文,而线程只需要改变程序的执行序列和局部变量。 +107.线程的缺陷: + *等待临界资源时效率降低 + *处理线程带来的额外CPU开销 + *增加了程序的复杂度 + *有可能产生病态行为,如饿死,竞争,死锁,活锁(多个线程各自运行导致无法完成整体任务)等 + *平台不一致性 -注:由于时间原因和过于复杂的内容跳过泛型一章P389页之后的内容、枚举类型一章,注解一章的内容,以后补完。 +注:由于时间原因和过于复杂的内容跳过泛型一章P389页之后的内容、枚举类型一章,注解一章的内容,以后补完。 From 43cc04191440aeab151e2c932fcdba09a0fde986 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 14 Mar 2014 22:52:05 +0800 Subject: [PATCH 225/327] rearrange --- 13.Java$keywords java.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/13.Java$keywords java.md b/13.Java$keywords java.md index 194cc69..37b8b58 100644 --- a/13.Java$keywords java.md +++ b/13.Java$keywords java.md @@ -129,7 +129,7 @@ *collection.iterator();获得当前容器的迭代器,相当于C++的containter.begin(); *collection.next();获取下一个迭代器位置,相当于C++的itr++; *collection.hasNext();检查序列中是否还有元素,相当于itr!=container.end(); -48.继承Collection就必须实现iterator()方法,该方法要求返回一个Iterator对象,可以使用匿名内部类方式返回该迭代器对象。 +48.继承Collection就必须实现iterator()方法,该方法要求返回一个Iterator< A >对象,可以使用匿名内部类方式返回该迭代器对象。 49.如果想要在foreach中使用某种容器类型(除数组外),要求该容器实现Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,实现iterator()的方法可以参考48。一个好的例子见Thinking in Java P243 50.使用Arrays.asList()需要谨慎,直接使用该方法返回的容器对象和使用该容器对象构造新的容器对象会产生不同的效果 *Integer[] ia = {1, 2, 3}; From 6db8f5327e194d28704dcfa82666bde92a86aefe Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 15 Mar 2014 10:45:07 +0800 Subject: [PATCH 226/327] add Ex7 --- 6.Tree&keywords tree, transform, visit.md | 156 ++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md index a5915e7..10c75e3 100644 --- a/6.Tree&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -271,3 +271,159 @@ public: } }; ``` + +Ex7:Tree Traversal 递归和非递归版本 +树的三种遍历方法的递归和非递归版本 + +```cpp +#include +#include +#include + +using namespace std; + +class TreeNode{ +public: + int val; + TreeNode * left; + TreeNode * right; + TreeNode(int val){ + this->val = val; + left = NULL; + right = NULL; + } +}; + +void preOrderTraversal(TreeNode * root); +void preOrderTraversalNonRecursive(TreeNode * root); +void inOrderTraversal(TreeNode * root); +void inOrderTraversalNonRecursive(TreeNode * root); +void postOrderTraversal(TreeNode * root); +void postOrderTraversalNonRecursive(TreeNode * root); + +int main(){ + TreeNode * n4 = new TreeNode(4); + TreeNode * n2 = new TreeNode(2); + TreeNode * n6 = new TreeNode(6); + + n4->left = n2; + n4->right = n6; + + TreeNode * n1 = new TreeNode(1); + TreeNode * n3 = new TreeNode(3); + + n2->left = n1; + n2->right = n3; + + TreeNode * n5 = new TreeNode(5); + TreeNode * n7 = new TreeNode(7); + + n6->left = n5; + n6->right = n7; + + cout<< "preOrderTraversal:"; + preOrderTraversal(n4); + cout<val << " "; + if(root->left != NULL) preOrderTraversal(root->left); + if(root->right != NULL) preOrderTraversal(root->right); +} + +void preOrderTraversalNonRecursive(TreeNode * root){ + stack stk; + for(;;){ + while(root != NULL){ + cout << root->val << " ";//visit + stk.push(root); + root = root->left; + } + if(!stk.empty()){ + root = stk.top(); + root = root->right; + stk.pop(); + }else{ + return; + } + } +} + +void inOrderTraversal(TreeNode * root){ + if(root == NULL){ + return; + } + if(root->left != NULL) inOrderTraversal(root->left); + cout << root->val << " "; + if(root->right != NULL) inOrderTraversal(root->right); +} + +void inOrderTraversalNonRecursive(TreeNode * root){ + stack stk; + for(;;){ + while(root != NULL){ + stk.push(root); + root = root->left; + } + if(!stk.empty()){ + root = stk.top(); + stk.pop(); + cout << root->val << " ";//visit + root = root->right; + }else{ + return; + } + } +} + +void postOrderTraversal(TreeNode * root){ + if(root == NULL){ + return; + } + if(root->left != NULL) postOrderTraversal(root->left); + if(root->right != NULL) postOrderTraversal(root->right); + cout << root->val << " "; +} + +void postOrderTraversalNonRecursive(TreeNode * root){ + stack stk; + TreeNode * lastVisit = NULL; + for(;;){ + while(root != NULL){ + stk.push(root); + root = root->left; + } + while(!stk.empty()){ + root = stk.top(); + if(root->right == lastVisit || root->right == NULL){ + cout << root->val << " ";//visit + lastVisit = root; + stk.pop(); + }else{ + root = root->right;//root can't be NULL here + break; + } + } + if(stk.empty()) return; + } +} +``` From 9b121cac0da279df3bb4da1e6f719a507dc34821 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 7 Apr 2014 09:44:07 +0800 Subject: [PATCH 227/327] update function isPalindrome() in Ex1 --- 2.String dp and Array dp$keywords dp.md | 47 ++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index b90b20c..40e9204 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -67,26 +67,33 @@ public class Solution { } ``` isPalindrome的dp解法: -```java - boolean[][] isPalindrome = new boolean[s.length()+1][s.length()+1]; - void isPalindrome(String s){ - for (int i=0; i Date: Mon, 7 Apr 2014 23:02:46 +0800 Subject: [PATCH 228/327] rewrite Ex3 and add a recursion solution to Ex3 --- 2.String dp and Array dp$keywords dp.md | 82 +++++++++++++++++-------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 40e9204..7aede6a 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -155,34 +155,64 @@ Ex3:[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matc ```cpp class Solution { public: - - bool isMatch(const char *s, const char *p) { - int len_s = strlen(s); - int len_p = strlen(p); - - const char* tmp = p; - int cnt = 0; - while (*tmp != '\0') if (*(tmp++) != '*') cnt++; - if (cnt > len_s) return false; - - bool dp[500][500]; - memset(dp, 0,sizeof(dp)); - - dp[0][0] = true; - for (int i = 1; i <= len_p; i++) { - if (dp[0][i-1] && p[i-1] == '*') dp[0][i] = true; - for (int j = 1; j <= len_s; ++j) - { - if (p[i-1] == '*') dp[j][i] = (dp[j-1][i] || dp[j][i-1]); - else if (p[i-1] == '?' || p[i-1] == s[j-1]) dp[j][i] = dp[j-1][i-1]; - else dp[j][i] = false; - } - } - return dp[len_s][len_p]; - } + bool isMatchDp(string& t, string& p){ + int tLen = t.length(); + int pLen = p.length(); + + bool dp[pLen+1][tLen+1]; + memset(dp, 0, sizeof(dp)); + + dp[0][0] = true; + + for(int i = 1; i <= pLen; i++){ + if(dp[i-1][0]&&p[i-1]=='*'){ + dp[i][0] = true; + } + } + + for(int i = 1; i <= pLen; i++){ + for(int j = 1; j <= tLen; j++){ + if((p[i-1] == '?')||p[i-1] == t[j-1]){ + dp[i][j] = dp[i-1][j-1]; + }else if(p[i-1] == '*'){ + dp[i][j] = dp[i-1][j]||dp[i][j-1]; + }else{ + dp[i][j] = false; + } + } + } + + return dp[pLen][tLen]; + } }; ``` - + +附该题的递归解法,时间复杂度高于dp方法,但是一个比较直观的思路。 +```cpp +//recursive +bool isMatch(string& t, string& p, int tPtr, int pPtr){ + if(p.length() == pPtr&&t.length() == tPtr) return true; + if(t.length() == tPtr||p.length() == pPtr) return false; + + if(p[pPtr] == '?'){ + return isMatch(t, p, tPtr+1, pPtr+1); + }else if(p[pPtr] == '*'){ + int tempPtr = tPtr; + while(tempPtr != t.length()+1){ + if(isMatch(t, p, tempPtr, pPtr+1)){ + return true; + } + tempPtr++; + } + return false; + }else if(p[pPtr] == t[tPtr]){ + return isMatch(t, p, tPtr+1, pPtr+1); + }else{ + return false; + } +} +``` + Ex4:[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/) 两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 From 72f53bea605fe112de2547503b798e6c6bf05c3f Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 10 Apr 2014 09:06:43 +0800 Subject: [PATCH 229/327] revise and update Ex1 --- 4.Search Array$keywords search.md | 86 ++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 31d736a..a4acfba 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -9,7 +9,7 @@ public class Solution { public int singleNumber(int[] A) { int one = 0, two = 0, erase = 0; for (int i = 0; i < A.length; i++) { - two ^= one & A[i]; + two |= one & A[i]; one ^= A[i]; erase = ~(one & two); two &= erase; @@ -20,7 +20,89 @@ public class Solution { } } ``` - +另外一个更直观更通用的解法是模拟法,但此种解法在OJ上可能超时。如下: +```cpp +#define ARY 3 + +int singleNumber(int A[], int n){ + int ret = 0; + int count[32]; + memset(count,0,sizeof(count)); + for(int i = 0; i <= 31; i++){ + int b = 1 << i; + for(int j = 0; j <= n-1; j++){ + if(A[j] & b){ + count[i]++; + } + } + if(count[i]%ARY){ + ret |= b; + } + } + return ret; +} +``` +在解决复杂同类问题时,这种方法更显得直观,如一组数据中出现两个不同的数字各一次(或k次),其余均出现a次,求出那两个数字,代码如下: +```cpp +int singleNumber(int A[], int n){ + int ret = 0; + int count[32]; + memset(count,0,sizeof(count)); + for(int i = 0; i <= 31; i++){ + int b = 1 << i; + for(int j = 0; j <= n-1; j++){ + if(A[j] & b){ + count[i]++; + } + } + if(count[i]%ARY){ + ret |= b; + } + } + return ret; +} + +int singleNumberSpecial(int A[], int n){ + int ret = 0; + int count[32]; + memset(count,0,sizeof(count)); + for(int i = 0; i <= 31; i++){ + int b = 1 << i; + for(int j = 0; j <= n-1; j++){ + if(A[j] & b){ + count[i]++; + } + } + if(count[i]%ARY == 1){ + ret |= b; + } + } + return ret; +} + +vector twoSingleNumber(int A[], int n){ + int twoNum = singleNumberSpecial(A, n); + int b = twoNum & (-twoNum); + int B[n],C[n]; + int bi = 0,ci = 0; + int single1 = 0, single2 = 0; + for(int i = 0; i <= n-1; i++){ + if(A[i] & b){ + B[bi++] = A[i]; + }else{ + C[ci++] = A[i]; + } + } + single1 = singleNumber(B, bi); + single2 = singleNumber(C, ci); + vector vec; + vec.push_back(single1); + vec.push_back(single2); + return vec; +} +``` +singleNumberSpecial()先找到两个数字不同的bit位,然后利用该bit位将数组分成两组,再应用之前的方法求解。 + Ex2:[Leetcode:Best Time to Buy and Sell Stock III](http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/) 分别记录到i时,0-i的最大利润和i+1到len-1的最大利润,相加即可。 From c00f08fbd57f302003228a2fd81b820a9329190d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Thu, 10 Apr 2014 17:16:07 +0800 Subject: [PATCH 230/327] =?UTF-8?q?add=20Cpp=20solution=20=E5=90=8CEX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 6.Tree&keywords tree, transform, visit.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md index 10c75e3..39f2316 100644 --- a/6.Tree&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -184,7 +184,24 @@ public class Solution { } } ``` - +C++版本代码 +```cpp +void recoveryTree(TreeNode * root, TreeNode *& lastNode){ + if(root == NULL) return; + + recoveryTree(root->left, lastNode); + + if(lastNode != NULL && root->val < lastNode->val){ + if(e1 == NULL){ + e1 = lastNode; + }else{ + e2 = root; + } + } + lastNode = root; + recoveryTree(root->right, lastNode); +} +``` Ex5:[Leetcode:Flatten Binary Tree to Linked List ](http://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/) 很明显需要采用先序遍历,使用一个指针记录上一个访问的节点,操作步骤为 From 78b001925913508c2e94c717e9c9df26020348fd Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 11 Apr 2014 09:12:23 +0800 Subject: [PATCH 231/327] update Ex5 --- 7.Area Computation$keyword stack.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index 745d710..7cbe965 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -195,7 +195,10 @@ public: Ex5:[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/) -此题虽然不是计算面积类型题,但因其采用的解题思想与Ex3和Ex4十分相似,即使用一个栈来维护历史状态,故而放于此处。 +此题虽然不是计算面积类型题,但因其采用的解题思想与Ex3和Ex4十分相似,即使用一个栈来维护历史状态。更准确的说,“连续的括号”这个状态当且仅当出现无法匹配的')'时才会发生,因此每次匹配成功时分成两种情况来考虑。 +* 栈为空:当前匹配成功位置与上次失配位置之间可能有0到多个匹配成功的括号对,因此i-last +* 栈不为空:尚有未被匹配的'(',此时的失配位置就是栈顶的'('的位置,因此i-lefts.top() + ```cpp class Solution { From f795583b70cb233caa4fa21a6df4ce05a113100e Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 11 Apr 2014 09:21:51 +0800 Subject: [PATCH 232/327] update Ex8, add Ex9, Ex10, Ex11, Ex12, Ex13 --- 8.Rewrite STL$keywords rewrite.md | 148 ++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 8 deletions(-) diff --git a/8.Rewrite STL$keywords rewrite.md b/8.Rewrite STL$keywords rewrite.md index aa029a6..9adecb7 100644 --- a/8.Rewrite STL$keywords rewrite.md +++ b/8.Rewrite STL$keywords rewrite.md @@ -257,20 +257,152 @@ public: } }; ``` -Ex8:strcpy +Ex8:strcpy +原型声明:char *strcpy(char* dest, const char *src); +头文件:#include +功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间 +说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,这些都需要调用者来保障。 +返回指向dest的指针。 + +一个较好的实现: ```cpp -char * strcpy(char * strDest, const char * strSrc) - { +char* strcpy(char* strDest, const char* strSrc){ + if(strDest == strSrc){ + return strDest; + } + assert((strDest != NULL) && (strSrc != NULL)); + char* address = strDest; + while((*strDest++ = *strSrc++)!='\0'); + return address; +} + +``` - if ((strDest == NULL) || (strSrc == NULL)) +Ex9:memcpy +原型声明:void *memcpy(void *dest, const void *src, size_t n); +头文件:C语言中使用#include ; + C++中使用#include 和#include 都可以 +功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中 +说明: +1.source和destin所指的内存区域可以重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针. +2.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。 +注意:source和destin都不一定是数组,任意的可读写的空间均可。 - throw "Invalid argument(s)"; +一个较好的实现: +```cpp +void * memcpy(void * destaddr,void const * srcaddr, size_t len){ + char* dest = destaddr; + const char * src = srcaddr; + while(len-- > 0){ + *dest++ = *src++; + } + return destaddr; +} + +``` - char * strDestCopy = strDest; +Ex10:memset +原型声明:void *memset(void *s, int ch, size_t n); +头文件: or memset wmemset +功能:将s中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s 。 +说明:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。 - while ((*strDest++ = *strSrc++) != '\0'); +一个较好的实现: +```cpp +void * memset(void *str, int c, size_t count){ + assert(str != NULL); + void *s = str; + while(count--){ + *(char*)s = (char) c; + s = (char*)s + 1; + } + return str; +} - return strDestCopy; +``` +错误使用示例: +1. +```cpp +int f(int a[]){ + memset(a,0,sizeof(a)); + } +``` +a会退化为指针,导致不能按照预想的方式初始化数组。 +2. +```cpp +int f(){ + int a[5]; + memset(a,1,20); + for(int i = 0; i < 5; i++){ + cout << a[i] << " "; + } + } +``` +由于memset是按照字节拷贝,因此a中的每个元素都会被初始化为0x01010101而不是1。 +3. +```cpp +int f(){ + char* s = "12345"; + memset(s,'1',5); } ``` +运行时错误,因为s指向的是常量区(不可写内存区域),对该区域的写操作会导致程序崩溃。换成char * s = new char[5];或者char s[] = "12345";则没有问题,前者是在堆上的可读写区域,后者是在栈上的可读写区域。 + +Ex11:strstr +原型声明:char *strstr(const char *str1, const char *str2); +头文件: +功能:该函数返回str2第一次在str1中的位置,如果没有找到,返回NULL +说明:注意两个参数均是const + +一个较好的实现: +```cpp +char* strstr(const char* strSrc, const char* str){ + assert(strSrc != NULL && str != NULL); + const char* s = strSrc; + const char* t = str; + for(; *strSrc != '\0'; strSrc++){ + for(s = strSrc, t = str; *t != '\0' && *s == *t; s++, t++){} + if(*t == '\0') return (char*)strSrc; + } + return NULL; +} + +``` + +Ex12:strcmp +原型声明:unsigned int strlen(const char *str); +头文件: +功能:返回以'\0'结尾的字符串长度,但不包括'\0' +说明:注意strlen只能接受char*的参数,不能与sizeof混淆 + +一个较好的实现: +```cpp +unsigned int strlen(const char* str){ + assert(str != NULL); + const char * eos = str; + while(*eos++); + return (unsigned int)(eos-str-1); +} + +``` + +Ex13:strcat +原型声明:char *strcat(char *dest, const char *src); +头文件: +功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。 +说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针。 + +一个较好的实现: +```cpp +char* strcat(char* dest, const char* src){ + assert((dest != NULL) && (src != NULL)); + char * ret = dest; + while(*dest){ + dest++; + } + while(*dest++ = *src++){} + return ret; +} + +``` From ffcf348bbb30ace5afd8aea2451fad65bf33f05e Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Wed, 16 Apr 2014 11:13:36 +0800 Subject: [PATCH 233/327] add Ex6 --- 0.Tricky Problems.md | 132 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index e149283..c4d05cc 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -187,3 +187,135 @@ public: } }; ``` + +Ex6:Outer Points of Rectangles +给定输入为vector,其中Rectangle的成员需要包括int x1,int x2和int y,也即在x-y坐标系中,所有Rectangles的底边都在x轴上,因此依靠这3个int值即可唯一确定Rectangle。现要求所有Rectangles组成的图形的外围点集。 +例如,对于输入: +Rectangle 1:(-4,2,2) +Rectangle 2:(-3,1,1) +Rectangle 3:(-3,-1,3) +Rectangle 4:(0,2,2) +Rectangle 5:(2,4,1) +输出点集: +(-4,0),(-3,2),(-3,3),(-1,3),(-1,1),(0,1),(0,2),(2,2),(2,1),(4,1),(4,0) +//TODO:解法解析 +代码如下: +```cpp +#include +#include +#include + +using namespace std; + +class Rectangle{ +public: + int x1; + int x2; + int y; + Rectangle(int _x1, int _x2, int _y){ + x1 = _x1; + x2 = _x2; + y = _y; + } + + bool operator == (const Rectangle & r) const{ + if(x1 == r.x1 && x2 == r.x2 && y == r.y){ + return true; + }else{ + return false; + } + } + + bool operator < (const Rectangle & r) const{ + if(y > r.y){//descending + return true; + }else{ + return false; + } + } +}; + +class Point{ +public: + int x; + int y; + int id;//1 or 2 + Rectangle * rec; + Point(int _x, int _y, int _id,Rectangle* _rec){ + x = _x; + y = _y; + id = _id; + rec = _rec; + } +}; + +bool cmp(const Point* p1, const Point* p2){ + if(p1->x < p2->x || (p1->x == p2->x && p1->y < p2->y)){ + return true; + }else{ + return false; + } +} + +int main(){ + vector inputVec; + inputVec.push_back(new Rectangle(-4,-2,2)); + inputVec.push_back(new Rectangle(-3,1,1)); + inputVec.push_back(new Rectangle(-3,-1,3)); + inputVec.push_back(new Rectangle(0,2,2)); + inputVec.push_back(new Rectangle(2,4,1)); + + vector pointVec; + for(int i = 0; i <= (int)(inputVec.size()-1); i++){ + pointVec.push_back(new Point(inputVec[i]->x1,inputVec[i]->y,1,inputVec[i])); + pointVec.push_back(new Point(inputVec[i]->x2,inputVec[i]->y,2,inputVec[i])); + } + + //sort points + sort(pointVec.begin(),pointVec.end(),cmp); + + set recSet; // RBT + recSet.clear(); + + vector ret;// answer + ret.clear(); + + int currentMaxHeight = 0;//current Highest + + for(int i = 0; i <= (int)(pointVec.size()-1); i++){ + if(pointVec[i]->id == 1){ + if(pointVec[i]->y > currentMaxHeight){ + ret.push_back(new Point(pointVec[i]->x,currentMaxHeight,0,NULL)); + ret.push_back(pointVec[i]); + }else if(pointVec[i]->y == currentMaxHeight){ + ret.push_back(pointVec[i]); + } + recSet.insert(*(pointVec[i]->rec)); + currentMaxHeight = (*(recSet.begin())).y;//update + }else if(pointVec[i]->id == 2){ + set::iterator itr = recSet.find(*(pointVec[i]->rec)); + if(itr != recSet.end()){ + recSet.erase(itr); + } + if(recSet.empty()){ + currentMaxHeight = 0; + }else{ + currentMaxHeight = (*(recSet.begin())).y;//update + } + + if(pointVec[i]->y > currentMaxHeight){ + ret.push_back(pointVec[i]); + ret.push_back(new Point(pointVec[i]->x,currentMaxHeight,0,NULL)); + }else if(pointVec[i]->y == currentMaxHeight){ + ret.push_back(pointVec[i]); + } + } + } + + //output + for(int i = 0; i <= (int)(ret.size()-1); i++){ + cout << "[" << ret[i]->x << "," << ret[i]->y << "]" << endl; + } +} +``` + From 0ec16d10661083e12fb0c2d1223c47fe32ab6028 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Wed, 16 Apr 2014 16:14:24 +0800 Subject: [PATCH 234/327] update Ex6 --- 0.Tricky Problems.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md index c4d05cc..8d4094a 100644 --- a/0.Tricky Problems.md +++ b/0.Tricky Problems.md @@ -189,7 +189,7 @@ public: ``` Ex6:Outer Points of Rectangles -给定输入为vector,其中Rectangle的成员需要包括int x1,int x2和int y,也即在x-y坐标系中,所有Rectangles的底边都在x轴上,因此依靠这3个int值即可唯一确定Rectangle。现要求所有Rectangles组成的图形的外围点集。 +给定输入为vector< Rectangle >,其中Rectangle的成员需要包括int x1,int x2和int y,也即在x-y坐标系中,所有Rectangles的底边都在x轴上,因此依靠这3个int值即可唯一确定Rectangle。现要求所有Rectangles组成的图形的外围点集。注意给定的Rectangle已按照x1排序。 例如,对于输入: Rectangle 1:(-4,2,2) Rectangle 2:(-3,1,1) @@ -198,7 +198,13 @@ Rectangle 4:(0,2,2) Rectangle 5:(2,4,1) 输出点集: (-4,0),(-3,2),(-3,3),(-1,3),(-1,1),(0,1),(0,2),(2,2),(2,1),(4,1),(4,0) -//TODO:解法解析 + +对于每个点(矩形的顶点)是否能形成外点取决于该点属于的Retangles区间。例如对于点(a,b)属于2个Retangles区间,也即Retangle 1:(x11,x12,y1)和Rectangle 2:(x21,x22,y2)其中x11<=a<=x12,x21<=a<=x22,如果b>=max(y1,y2),则点(a,b)是外点,且可能额外生成一个交点(a,max(y1,y2)),这个点也是外点。因此问题就转变为对于每个点,如何维持该点所属Retangles区间,考虑使用set。set的底层实现是RBT,对于动态的维护一个集合的最值比较适合,每次操作代价仅为logn。具体做法是: +* 如果该点是某矩形的第一个点(左上角),则计算该点是否是外点,并决定是否生成额外的外点,然后将该矩形加入set,并更新当前最大值 +* 如果该点是某矩形的第二个点(右上角),则在set中查找该矩形,删除它并更新当前最大值,然后计算该点是否是外点,并决定是否生成额外的外点 + +注意对Rectangle的"=="和"<"进行重载。 + 代码如下: ```cpp #include From c10c6c6fb7e2a6049ae3357536f4626f135a323f Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Wed, 14 May 2014 16:10:15 +0800 Subject: [PATCH 235/327] add Ex14: QuickSort in Linklist --- 8.Rewrite STL$keywords rewrite.md | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/8.Rewrite STL$keywords rewrite.md b/8.Rewrite STL$keywords rewrite.md index 9adecb7..8cd87d7 100644 --- a/8.Rewrite STL$keywords rewrite.md +++ b/8.Rewrite STL$keywords rewrite.md @@ -406,3 +406,67 @@ char* strcat(char* dest, const char* src){ } ``` + +Ex14:QuickSort in Linklist +主要思路是在做partition的时候将链表分为三个部分,做递归之前注意将每一段的尾部置空,合并时注意判断边界条件。 +```cpp +#include + +using namespace std; + +class ListNode{ +public: + int val; + ListNode * next; + ListNode(int _val):val(_val),next(NULL){} +}; + +ListNode * quickSort(ListNode * head){ + if(head == NULL || head->next == NULL){ + return head; + } + ListNode dummyFront(-1), dummyMid(-1), dummyBack(-1); + ListNode * frontTail = NULL, * midTail = NULL, * backTail = NULL; + int num = head->val; + for(ListNode * itr = head; itr != NULL; itr = itr->next){ + if(itr->val == num){ + if(midTail == NULL){ + dummyMid.next = itr; + midTail = itr; + }else{ + midTail->next = itr; + midTail = midTail->next; + } + }else if(itr->val < num){ + if(frontTail == NULL){ + dummyFront.next = itr; + frontTail = itr; + }else{ + frontTail->next = itr; + frontTail = frontTail->next; + } + }else{ + if(backTail == NULL){ + dummyBack.next = itr; + backTail = itr; + }else{ + backTail->next = itr; + backTail = backTail->next; + } + } + } + if(frontTail != NULL) frontTail->next = NULL; + if(midTail != NULL) midTail->next = NULL; + if(backTail != NULL) backTail->next = NULL; + ListNode * frontRet = quickSort(dummyFront.next); + ListNode * backRet = quickSort(dummyBack.next); + ListNode * ret = frontRet == NULL ?dummyMid.next:frontRet; + if(frontRet != NULL){ + ListNode * itr = NULL; + for(itr = frontRet; itr->next != NULL; itr = itr->next){} + itr->next = dummyMid.next; + } + midTail->next = backRet; + return ret; +} +``` From 94463d0fadd3011e2eb25d7b3c715685c5e17d8d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 1 Sep 2014 11:09:40 +0800 Subject: [PATCH 236/327] first commit --- 14.Probability.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 14.Probability.md diff --git a/14.Probability.md b/14.Probability.md new file mode 100644 index 0000000..039edac --- /dev/null +++ b/14.Probability.md @@ -0,0 +1,75 @@ +##概率问题 + +本章收录了一些概率相关问题。 + +Ex1:已知元素个数n,按顺序等概率的选出m个元素(m= 1 && r <= k){ + pick[r-1] = i+1; + } + } +} +1号结点被选取的概率,遍历到1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +2号结点被选取的概率,遍历到2号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +…… +k+1号结点被选取的概率,遍历到k+1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +…… +最后一个结点被选取的概率,遍历到N号结点时被选中:K/N +从1~N依次计算每个i被最终选取的概率,发现都是K/N。 + +Ex3:等概率随机排列数组(洗牌算法) +假设有一个数组,包含n个元素。现在要重新排列这些元素,要求每个元素被放到任何一个位置的概率都相等(即1/n),并且直接在数组上重排(in place),不要生成新的数组。用O(n) 时间、O(1)辅助空间。 +先想想如果可以开辟另外一块长度为n的辅助空间时该怎么处理,显然只要对n个元素做n次(不放回的)随机抽取就可以了。先从n个元素中任选一个,放入新空间的第一个位置,然后再从剩下的n-1个元素中任选一个,放入第二个位置,依此类推。 +按照同样的方法,但这次不开辟新的存储空间。第一次被选中的元素就要放入这个数组的第一个位置,但这个位置原来已经有别的(也可能就是这个)元素了,这时候只要把原来的元素跟被选中的元素互换一下就可以了。很容易就避免了辅助空间 + +Ex4:利用等概率函数Rand5产生等概率函数Rand3 +```cpp +int Rand3(){ + int x; + do{ + x = Rand5(); + }while(x >= 3); + return x;//0,2,1 +} +``` +只要保证返回的3个数是等概率的即可,每个数的概率都为1/5 + +Ex5:利用等概率函数Rand5产生等概率函数Rand7 +```cpp +int Rand7(){ + int x; + do{ + x = Rand()5*5+Rand5(); + }while(x >= 7); + return x; +} +``` +先生成一个比目标大的概率函数,然后在采用之前的方法即可。在生成较大的目标概率函数时,可以使用RandA()*B+RandB()的形式,可保证不重不漏,且每个数产生的概率相同。 +更一般化的:于已知的RandX()函数,可以使用模拟X进制生成一个比目标大的概率函数 +如X^3RandX()+X^2RandX()+XRandX()+RandX()可以保证不重不漏,因而能等概率的生成数字 + +pi=n−1n×n−2n−1×⋯×n−i+1n−i+2×1n−i+1=1n + + From e31227c0d223d1e443f945694b651ed932fe4bef Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 1 Sep 2014 11:12:10 +0800 Subject: [PATCH 237/327] Update 14.Probability.md --- 14.Probability.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/14.Probability.md b/14.Probability.md index 039edac..9bb83c8 100644 --- a/14.Probability.md +++ b/14.Probability.md @@ -2,7 +2,8 @@ 本章收录了一些概率相关问题。 -Ex1:已知元素个数n,按顺序等概率的选出m个元素(m Date: Mon, 1 Sep 2014 11:15:21 +0800 Subject: [PATCH 238/327] Update 14.Probability.md --- 14.Probability.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/14.Probability.md b/14.Probability.md index 9bb83c8..8915f29 100644 --- a/14.Probability.md +++ b/14.Probability.md @@ -1,4 +1,4 @@ -##概率问题 +##Probability 本章收录了一些概率相关问题。 @@ -35,12 +35,10 @@ void pickK(int A[],int n,int k){ } } ``` -1号结点被选取的概率,遍历到1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N -2号结点被选取的概率,遍历到2号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N -…… -k+1号结点被选取的概率,遍历到k+1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N -…… -最后一个结点被选取的概率,遍历到N号结点时被选中:K/N +1号结点被选取的概率,遍历到1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +2号结点被选取的概率,遍历到2号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +k+1号结点被选取的概率,遍历到k+1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +最后一个结点被选取的概率,遍历到N号结点时被选中:K/N 从1~N依次计算每个i被最终选取的概率,发现都是K/N。 Ex3:等概率随机排列数组(洗牌算法) From 8d90e10e14687251055a23306bcf9886de1b308a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 1 Sep 2014 11:25:51 +0800 Subject: [PATCH 239/327] Update 14.Probability.md --- 14.Probability.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/14.Probability.md b/14.Probability.md index 8915f29..6a04a95 100644 --- a/14.Probability.md +++ b/14.Probability.md @@ -68,10 +68,12 @@ int Rand7(){ return x; } ``` -先生成一个比目标大的概率函数,然后在采用之前的方法即可。在生成较大的目标概率函数时,可以使用RandA()*B+RandB()的形式,可保证不重不漏,且每个数产生的概率相同。 -更一般化的:于已知的RandX()函数,可以使用模拟X进制生成一个比目标大的概率函数 -如X^3RandX()+X^2RandX()+XRandX()+RandX()可以保证不重不漏,因而能等概率的生成数字 +先生成一个比目标大的概率函数,然后在采用之前的方法即可。在生成较大的目标概率函数时,可以使用RandA()*B+RandB()的形式,可保证不重不漏,且每个数产生的概率相同。 -pi=n−1n×n−2n−1×⋯×n−i+1n−i+2×1n−i+1=1n +更一般化的:于已知的RandX()函数,可以使用模拟X进制生成一个比目标大的概率函数,如 +- X^3RandX()+X^2RandX()+XRandX()+RandX() + +可以保证不重不漏,因而能等概率的生成数字 +- pi=n−1n×n−2n−1×⋯×n−i+1n−i+2×1n−i+1=1n From b4bb59621f0c50b01d9addb1d21cfe8c0d4ae586 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Mon, 1 Sep 2014 15:28:52 +0800 Subject: [PATCH 240/327] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fec4f8d..3959a40 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ Chapters 10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata 11.[String](11.String$keywords string.md)$keywords string 12.[Greedy](12.Greedy$keywords greedy.md)$keywords greedy -13.[Java](Java$keywords java.md)$keywords java - +13.[Java](13.Java$keywords java.md)$keywords java +14.[Probability](14.Probability.md)$keywords probability Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 82502f7f1652582968289d2d6c29059e8b0c9a2b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 13 Sep 2014 16:16:00 +0800 Subject: [PATCH 241/327] update e-mail address --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3959a40..927d71b 100644 --- a/README.md +++ b/README.md @@ -27,5 +27,5 @@ Core contributors [@popolou](https://github.com/popolou) Contact us ------------ -欢迎提出意见和建议到sc1_1@bupt.edu.cn . +欢迎提出意见和建议到sc1_1@163.com . From f3e91d01a9dd68c87ace4116ea77cd42c1ab4684 Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 18 Oct 2014 21:42:28 +0800 Subject: [PATCH 242/327] =?UTF-8?q?Create=20=E5=A4=A7=E5=9E=8B=E7=BD=91?= =?UTF-8?q?=E7=AB=99=E5=BC=80=E5=8F=91.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 初稿 --- ...\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 "\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" diff --git "a/\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" "b/\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" new file mode 100644 index 0000000..afad75c --- /dev/null +++ "b/\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" @@ -0,0 +1,2 @@ +##1.多线程 +###[锁](http://blog.csdn.net/natian306/article/details/18504111) From e95da7c3d646ef563a001ef52d91bc19851db92d Mon Sep 17 00:00:00 2001 From: popolou Date: Sat, 18 Oct 2014 21:44:04 +0800 Subject: [PATCH 243/327] =?UTF-8?q?Rename=20=E5=A4=A7=E5=9E=8B=E7=BD=91?= =?UTF-8?q?=E7=AB=99=E5=BC=80=E5=8F=91.md=20to=2015.=E5=A4=A7=E5=9E=8B?= =?UTF-8?q?=E7=BD=91=E7=AB=99=E5=BC=80=E5=8F=91.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" => "15.\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" (100%) diff --git "a/\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" "b/15.\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" similarity index 100% rename from "\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" rename to "15.\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" From 29db4694f86a82b5b3150818d18dbee5ed565465 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 20:17:36 +0800 Subject: [PATCH 244/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 927d71b..0ef991a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -AlgorithmNote +AlgorithmNote(Our github blog is about to refactor recently) ============= Introduction ------------ From 4965d9c26bd908b0969b7aa22de0148f0396c37d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:17:32 +0800 Subject: [PATCH 245/327] Update README.md --- README.md | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 0ef991a..7c19fdf 100644 --- a/README.md +++ b/README.md @@ -2,30 +2,31 @@ AlgorithmNote(Our github blog is about to refactor recently) ============= Introduction ------------ -AlgorithmNote是一个按照主题分类的用于记录、整理和分享算法思路和解法Github项目,旨在分享有趣,具有思维性的算法问题和解答方法。 - +AlgorithmNote是一个知识分享Github,主要包括算法、工程和基础知识三大部分,欢迎任何人发送Pull Request。 +AlgorithmNote is a knowledge sharing github page, mainly has three parts: algorithm, engineering and basic knowledge. +Anyone is welcomed and encouraged to send pull request. Chapters ------------ -0.[Tricky Problems](0.Tricky Problems.md) -1.[Permutations and Combinations](1.Permutations and Combinations$keywords Permutation, Combination.md)$keywords Permutation, Combination -2.[String dp and array dp](2.String dp and Array dp$keywords dp.md)$keywords dp -3.[Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)$keywords Vector Sum, Tree Sum, Other Sum -4.[Search Array](4.Search Array$keywords search.md)$keywords search -5.[Graph](5.Graph&keywords graph.md)$keywords graph -6.[Tree transform and Tree search](6.Tree&keywords tree, transform, visit.md)$keywords tree, transform, search -7.[Area Computation](7.Area Computation$keyword stack.md)$keyword stack -8.[Rewrite STL](8.Rewrite STL$keywords Rewrite.md)$keywords Rewrite -9.[Sliding window](9.Sliding window$keywords window.md)$keywords window -10.[Big Data Processing](10. Big Data Processing$keywords Bigdata.md)$keywords Bigdata -11.[String](11.String$keywords string.md)$keywords string -12.[Greedy](12.Greedy$keywords greedy.md)$keywords greedy -13.[Java](13.Java$keywords java.md)$keywords java -14.[Probability](14.Probability.md)$keywords probability +Algorithm +~~~~~~~~~ +1. Array & String +2. Dynamic Programming +3. Greedy Strategy +4. Tree & Linkedlist +5. BFS & DFS +6. STL related +7. Others +Engineering +~~~~~~~~~~ +1. Website construction +Basic Knowledge +~~~~~~~~~~ +1. Basic Java Concepts Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) [@popolou](https://github.com/popolou) Contact us ------------ -欢迎提出意见和建议到sc1_1@163.com . - +欢迎提出意见和建议到sc1_1@163.com. +Any advice is appreciated, please send email to sc1_1@163.com. From 583d40f4fcfffea24377599137aa717f9a7e0349 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:46:56 +0800 Subject: [PATCH 246/327] Update README.md --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7c19fdf..58ec47a 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,7 @@ AlgorithmNote is a knowledge sharing github page, mainly has three parts: algori Anyone is welcomed and encouraged to send pull request. Chapters ------------ -Algorithm -~~~~~~~~~ +####Algorithm 1. Array & String 2. Dynamic Programming 3. Greedy Strategy @@ -16,11 +15,11 @@ Algorithm 5. BFS & DFS 6. STL related 7. Others -Engineering -~~~~~~~~~~ + +####Engineering 1. Website construction -Basic Knowledge -~~~~~~~~~~ + +####Basic Knowledge 1. Basic Java Concepts Core contributors ------------ From 78546d139252dbf3468a6ec0fa6a91a4b9f9c581 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:47:30 +0800 Subject: [PATCH 247/327] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 58ec47a..4c159ca 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Chapters ####Basic Knowledge 1. Basic Java Concepts + Core contributors ------------ [@sc703bupt](https://github.com/sc703bupt) From 9b37016f14d251c868475a8d094f97a0b0581b3e Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:48:37 +0800 Subject: [PATCH 248/327] Create Array and String.md --- Array and String.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Array and String.md diff --git a/Array and String.md b/Array and String.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Array and String.md @@ -0,0 +1 @@ +NULL From 10ff4f24b8d7ab41042cd3b85f9f281e1ad0e5c4 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:49:20 +0800 Subject: [PATCH 249/327] Rename Array and String.md to Array & String.md --- Array and String.md => Array & String.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Array and String.md => Array & String.md (100%) diff --git a/Array and String.md b/Array & String.md similarity index 100% rename from Array and String.md rename to Array & String.md From f1a189c45007062ed538a754d36025e91203344c Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:50:16 +0800 Subject: [PATCH 250/327] Create Dynamic Programming --- Dynamic Programming | 1 + 1 file changed, 1 insertion(+) create mode 100644 Dynamic Programming diff --git a/Dynamic Programming b/Dynamic Programming new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Dynamic Programming @@ -0,0 +1 @@ +NULL From f386ce973fd10bf7af7893ca6ef08d75cc40d500 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:50:32 +0800 Subject: [PATCH 251/327] Rename Dynamic Programming to Dynamic Programming.md --- Dynamic Programming => Dynamic Programming.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Dynamic Programming => Dynamic Programming.md (100%) diff --git a/Dynamic Programming b/Dynamic Programming.md similarity index 100% rename from Dynamic Programming rename to Dynamic Programming.md From f6e781ad906db67916752e905dc9e4d937cf5e0a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:51:24 +0800 Subject: [PATCH 252/327] Create Greedy Strategy.md --- Greedy Strategy.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Greedy Strategy.md diff --git a/Greedy Strategy.md b/Greedy Strategy.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Greedy Strategy.md @@ -0,0 +1 @@ +NULL From 09ea3e09464e6cf08abd6adbea80b43d158cc8d4 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:51:52 +0800 Subject: [PATCH 253/327] Create Tree & Linkedlist.md --- Tree & Linkedlist.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Tree & Linkedlist.md diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Tree & Linkedlist.md @@ -0,0 +1 @@ +NULL From 84c19f10e9c34681260e53143c498d56a843286e Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:52:17 +0800 Subject: [PATCH 254/327] Create BFS & DFS.md --- BFS & DFS.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 BFS & DFS.md diff --git a/BFS & DFS.md b/BFS & DFS.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/BFS & DFS.md @@ -0,0 +1 @@ +NULL From 4b97849b5fbff29b48bdae88716e44e60c108b78 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:53:25 +0800 Subject: [PATCH 255/327] Create STL related.md --- STL related.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 STL related.md diff --git a/STL related.md b/STL related.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/STL related.md @@ -0,0 +1 @@ +NULL From fb8e4b1fa5bba2b5083158c43aa2db2c1e12a21a Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:54:06 +0800 Subject: [PATCH 256/327] Create Others.md --- Others.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Others.md diff --git a/Others.md b/Others.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Others.md @@ -0,0 +1 @@ +NULL From fbe34d2187e2d6033c2de227b962e7aa17cdd21b Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:58:03 +0800 Subject: [PATCH 257/327] add links --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4c159ca..be23be0 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ Anyone is welcomed and encouraged to send pull request. Chapters ------------ ####Algorithm -1. Array & String -2. Dynamic Programming -3. Greedy Strategy -4. Tree & Linkedlist -5. BFS & DFS -6. STL related -7. Others +1. [Array & String](Array & String.md) +2. [Dynamic Programming](Dynamic Programming.md) +3. [Greedy Strategy](Greedy Strategy.md) +4. [Tree & Linkedlist](Tree & Linkedlist.md) +5. [BFS & DFS](BFS & DFS.md) +6. [STL related](STL related.md) +7. [Others](Others.md) ####Engineering 1. Website construction From aafa09a0ebec445f13dcc090f0a9b626787a22ce Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 21:59:24 +0800 Subject: [PATCH 258/327] Create Basic Java Concepts.md --- Basic Java Concepts.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Basic Java Concepts.md diff --git a/Basic Java Concepts.md b/Basic Java Concepts.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Basic Java Concepts.md @@ -0,0 +1 @@ +NULL From 80118eef74d8583f916adb22f902f77e6c221f72 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 22:00:29 +0800 Subject: [PATCH 259/327] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index be23be0..a287ff2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ AlgorithmNote(Our github blog is about to refactor recently) Introduction ------------ AlgorithmNote是一个知识分享Github,主要包括算法、工程和基础知识三大部分,欢迎任何人发送Pull Request。 + AlgorithmNote is a knowledge sharing github page, mainly has three parts: algorithm, engineering and basic knowledge. Anyone is welcomed and encouraged to send pull request. Chapters @@ -20,7 +21,7 @@ Chapters 1. Website construction ####Basic Knowledge -1. Basic Java Concepts +1. [Basic Java Concepts](Basic Java Concepts.md) Core contributors ------------ @@ -29,4 +30,5 @@ Core contributors Contact us ------------ 欢迎提出意见和建议到sc1_1@163.com. + Any advice is appreciated, please send email to sc1_1@163.com. From bc6e0e6630c55900a043e7e0384c903e0a9dda92 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 23:56:12 +0800 Subject: [PATCH 260/327] Update Array & String.md --- Array & String.md | 110 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/Array & String.md b/Array & String.md index 7951def..4804265 100644 --- a/Array & String.md +++ b/Array & String.md @@ -1 +1,109 @@ -NULL +##Array & String +Index: +1.[single number II](#Anchor1) +2.[Combination](#Anchor2) + + +1.[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/) + +两个变量,ones和twos,顺序遍历并且求出异或值,ones表示异或值哪些位 比特1出现一次,twos表示异或值哪些位 比特1出现两次,当异或值的某些位 比特1出现三次的时候,就要对其进行清除,这样就能保证最后得到的ones就是出现一次的数 +```java +public class Solution { + public int singleNumber(int[] A) { + int one = 0, two = 0, erase = 0; + for (int i = 0; i < A.length; i++) { + two |= one & A[i]; + one ^= A[i]; + erase = ~(one & two); + two &= erase; + one &= erase; + } + + return one; + } +} +``` +另外一个更直观更通用的解法是模拟法,但此种解法在OJ上可能超时。如下: +```cpp +#define ARY 3 + +int singleNumber(int A[], int n){ + int ret = 0; + int count[32]; + memset(count,0,sizeof(count)); + for(int i = 0; i <= 31; i++){ + int b = 1 << i; + for(int j = 0; j <= n-1; j++){ + if(A[j] & b){ + count[i]++; + } + } + if(count[i]%ARY){ + ret |= b; + } + } + return ret; +} +``` +在解决复杂同类问题时,这种方法更显得直观,如一组数据中出现两个不同的数字各一次(或k次),其余均出现a次,求出那两个数字,代码如下: +```cpp +int singleNumber(int A[], int n){ + int ret = 0; + int count[32]; + memset(count,0,sizeof(count)); + for(int i = 0; i <= 31; i++){ + int b = 1 << i; + for(int j = 0; j <= n-1; j++){ + if(A[j] & b){ + count[i]++; + } + } + if(count[i]%ARY){ + ret |= b; + } + } + return ret; +} + +int singleNumberSpecial(int A[], int n){ + int ret = 0; + int count[32]; + memset(count,0,sizeof(count)); + for(int i = 0; i <= 31; i++){ + int b = 1 << i; + for(int j = 0; j <= n-1; j++){ + if(A[j] & b){ + count[i]++; + } + } + if(count[i]%ARY == 1){ + ret |= b; + } + } + return ret; +} + +vector twoSingleNumber(int A[], int n){ + int twoNum = singleNumberSpecial(A, n); + int b = twoNum & (-twoNum); + int B[n],C[n]; + int bi = 0,ci = 0; + int single1 = 0, single2 = 0; + for(int i = 0; i <= n-1; i++){ + if(A[i] & b){ + B[bi++] = A[i]; + }else{ + C[ci++] = A[i]; + } + } + single1 = singleNumber(B, bi); + single2 = singleNumber(C, ci); + vector vec; + vec.push_back(single1); + vec.push_back(single2); + return vec; +} +``` +singleNumberSpecial()先找到两个数字不同的bit位,然后利用该bit位将数组分成两组,再应用之前的方法求解。 + + From 08342e185990720c68c46d7737f4d2a50970a3ef Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Fri, 24 Oct 2014 23:58:31 +0800 Subject: [PATCH 261/327] Update Array & String.md --- Array & String.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Array & String.md b/Array & String.md index 4804265..a6ec8a6 100644 --- a/Array & String.md +++ b/Array & String.md @@ -1,10 +1,10 @@ ##Array & String Index: -1.[single number II](#Anchor1) -2.[Combination](#Anchor2) +-[Leetcode:single number II](#Anchor1) +-[Combination](#Anchor2) -1.[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/) +-[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/) 两个变量,ones和twos,顺序遍历并且求出异或值,ones表示异或值哪些位 比特1出现一次,twos表示异或值哪些位 比特1出现两次,当异或值的某些位 比特1出现三次的时候,就要对其进行清除,这样就能保证最后得到的ones就是出现一次的数 ```java From 6bf06718e3bcb1047a17b1a6c68af9afb4bc4e06 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 00:16:33 +0800 Subject: [PATCH 262/327] Update Array & String.md --- Array & String.md | 166 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-) diff --git a/Array & String.md b/Array & String.md index a6ec8a6..ff1bbb6 100644 --- a/Array & String.md +++ b/Array & String.md @@ -1,10 +1,12 @@ ##Array & String Index: -[Leetcode:single number II](#Anchor1) --[Combination](#Anchor2) +-[Find Reverse Pair](#Anchor2) +-[Find Min K](#Anchor3) +-[Find Number occurs half times](#Anchor4) --[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/) +-**[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/)** 两个变量,ones和twos,顺序遍历并且求出异或值,ones表示异或值哪些位 比特1出现一次,twos表示异或值哪些位 比特1出现两次,当异或值的某些位 比特1出现三次的时候,就要对其进行清除,这样就能保证最后得到的ones就是出现一次的数 ```java @@ -107,3 +109,163 @@ vector twoSingleNumber(int A[], int n){ singleNumberSpecial()先找到两个数字不同的bit位,然后利用该bit位将数组分成两组,再应用之前的方法求解。 +-**Find Reverse Pair** +问题描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 +使用普通的比较时间复杂度是n方。这里介绍一种复杂度为nlogn的方法。该方法要借助归并排序,即将数组分为两部分分别排序,然后merge。之后在对两个子数组进行merge的时候,去比较子数组1的当前元素和子数组2的当前元素,若1大于2,则说明1后面的元素都大于2,所以都为逆序对,将这些数加入结果集。 +```java +public class Main { + static long count = 0; + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + while (in.hasNext()) { + int n = in.nextInt(); + int[] a = new int[n]; + for (int i = 0; i < n; i++) + a[i] = in.nextInt(); + count = 0; + mergeSort(a); + System.out.println(count); + } + } + + // 将有二个有序数列a[first...mid]和a[mid...last]合并。 + static void mergearray(int a[], int first, int mid, int last, int temp[]) { + int i = first, j = mid + 1; + int m = mid, n = last; + int k = 0; + while (i <= m && j <= n) { + if (a[i] > a[j]) { + // 左数组比右数组大 + temp[k++] = a[j++]; + // 因为如果a[i]此时比右数组的当前元素a[j]大, + // 那么左数组中a[i]后面的元素就都比a[j]大 + // 【因为数组此时是有序数组】 + count += mid - i + 1; + } else { + temp[k++] = a[i++]; + } + } + while (i <= m) { + temp[k++] = a[i++]; + } + while (j <= n) { + temp[k++] = a[j++]; + } + for (i = 0; i < k; i++) + a[first + i] = temp[i]; + } + + static void mergesort(int a[], int first, int last, int temp[]) { + if (first < last) { + int mid = (first + last) / 2; + mergesort(a, first, mid, temp); // 左边有序 + mergesort(a, mid + 1, last, temp); // 右边有序 + mergearray(a, first, mid, last, temp); // 再将二个有序数列合并 + } + } + + static void mergeSort(int a[]) { + int[] p = new int[a.length]; + mergesort(a, 0, a.length - 1, p); + } +} +``` + + +-**Find Min K** +问题描述:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 + +Solution 1: +在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组。时间复杂度O(n)。 +```cpp +#include +#include +#include +#include +using namespace std; +#define LL long long +void swap(LL *a, LL *b){ + LL tmp=*a; + *a=*b; + *b=tmp; +} + +int partition_arr(int low,int high,LL *arr,const int k){ + if(low>=high) + return 0; + LL tmp=arr[low]; + int i=low,j=high+1; + LL pivot=arr[low]; + while(1){ + while(arr[++i]pivot); + if(i=k){ + printf("%d",arr[0]); + for(i=1;i +-**Find Number occurs half times** +问题描述:找出出现次数刚好是一半的数字。有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。 +首先,该数字占总数的一半(假设为x),说明总数必为偶数;其次,最后一个元素或者是x,或者不是x,因此只要在扫描数组的时候每一个元素都与最后一个元素做比较,如果相等则最后一个元素的个数加1,否则不处理。如果最后一个元素的个数为N/2,(N为数组元素个数)则它就是x,否则x就是前面N-1个元素中选出的candidate。 +```cpp +int MoreThanHalf(int a[], int N) +{ + int sum1 = 0;//最后一个元素的个数 + int sum2 = 0; + int candidate; + int i; + for(i=0;i Date: Sat, 25 Oct 2014 00:25:39 +0800 Subject: [PATCH 263/327] Moving all suitable cases from original 4.Search Array --- Array & String.md | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/Array & String.md b/Array & String.md index ff1bbb6..db145f6 100644 --- a/Array & String.md +++ b/Array & String.md @@ -1,12 +1,14 @@ ##Array & String + Index: -[Leetcode:single number II](#Anchor1) -[Find Reverse Pair](#Anchor2) -[Find Min K](#Anchor3) -[Find Number occurs half times](#Anchor4) +-[Leetcode:Median of Two Sorted Arrays](#Anchor5) --**[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/)** +-**[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/)**([Back to Index](#AnchorIndex)) 两个变量,ones和twos,顺序遍历并且求出异或值,ones表示异或值哪些位 比特1出现一次,twos表示异或值哪些位 比特1出现两次,当异或值的某些位 比特1出现三次的时候,就要对其进行清除,这样就能保证最后得到的ones就是出现一次的数 ```java @@ -109,7 +111,7 @@ vector twoSingleNumber(int A[], int n){ singleNumberSpecial()先找到两个数字不同的bit位,然后利用该bit位将数组分成两组,再应用之前的方法求解。 --**Find Reverse Pair** +-**Find Reverse Pair**([Back to Index](#AnchorIndex)) 问题描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 使用普通的比较时间复杂度是n方。这里介绍一种复杂度为nlogn的方法。该方法要借助归并排序,即将数组分为两部分分别排序,然后merge。之后在对两个子数组进行merge的时候,去比较子数组1的当前元素和子数组2的当前元素,若1大于2,则说明1后面的元素都大于2,所以都为逆序对,将这些数加入结果集。 ```java @@ -173,7 +175,7 @@ public class Main { ``` --**Find Min K** +-**Find Min K**([Back to Index](#AnchorIndex)) 问题描述:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 Solution 1: @@ -234,7 +236,7 @@ Solution 2: //TODO(堆排序) --**Find Number occurs half times** +-**Find Number occurs half times**([Back to Index](#AnchorIndex)) 问题描述:找出出现次数刚好是一半的数字。有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。 首先,该数字占总数的一半(假设为x),说明总数必为偶数;其次,最后一个元素或者是x,或者不是x,因此只要在扫描数组的时候每一个元素都与最后一个元素做比较,如果相等则最后一个元素的个数加1,否则不处理。如果最后一个元素的个数为N/2,(N为数组元素个数)则它就是x,否则x就是前面N-1个元素中选出的candidate。 ```cpp @@ -268,4 +270,35 @@ int MoreThanHalf(int a[], int N) return candidate; } ``` + +-**[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/)**(#AnchorIndex)) +每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代,这样每次能去除掉一半的元素,时间复杂度为O(log(m+n))。 +```java +class Solution { +public: + double findMedianSortedArrays(int A[], int m, int B[], int n) { + int total = m + n; + if (total & 0x1) + return find_kth(A, m, B, n, total / 2 + 1); + else + return (find_kth(A, m, B, n, total / 2) + + find_kth(A, m, B, n, total / 2 + 1)) / 2; + } +private: + + static double find_kth(int A[], int m, int B[], int n, int k) { + //always assume that m is equal or smaller than n + if (m > n) return find_kth(B, n, A, m, k); + if (m == 0) return B[k - 1]; + if (k == 1) return min(A[0], B[0]); + //divide k into two parts + int pa = min(k / 2, m), pb = k - pa; + if (A[pa - 1] < B[pb - 1]) + return find_kth(A + pa, m - pa, B, n, k - pa); + else if (A[pa - 1] > B[pb - 1]) + return find_kth(A, m, B + pb, n - pb, k - pb); + else + return A[pa - 1]; + } +}; From 64dcf1568d2fc5bfc11b6bafb3dab053d3a02a58 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 09:47:05 +0800 Subject: [PATCH 264/327] Update Array & String.md --- Array & String.md | 48 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/Array & String.md b/Array & String.md index db145f6..ef99902 100644 --- a/Array & String.md +++ b/Array & String.md @@ -4,7 +4,7 @@ Index: -[Leetcode:single number II](#Anchor1) -[Find Reverse Pair](#Anchor2) -[Find Min K](#Anchor3) --[Find Number occurs half times](#Anchor4) +-[Find Number occurs half times](#Anchor4) -[Leetcode:Median of Two Sorted Arrays](#Anchor5) @@ -179,7 +179,7 @@ public class Main { 问题描述:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 Solution 1: -在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组。时间复杂度O(n)。 +在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组。该算法叫做Quick Select,时间复杂度O(n)。 ```cpp #include #include @@ -233,7 +233,45 @@ int main() ``` Solution 2: -//TODO(堆排序) +求解Min K也可以使用堆排序,使用容量为K大根堆,初始时,使用数组的前K个元素建堆,然后对N-K个元素进行如下操作: + + if A[i] >= heap.top + continue + else + pop the heap.top + insert A[i] to heap + +这里的操作说明大根堆里时刻维护的是下标为0到i-1中最小的K个数,如果后续某个数小于这K个数中最大的数,则应该取代该数并成为最小的K个数中的一员。该算法的时间复杂度为O(K+(N-K)logK),空间复杂度为O(K)。 +```cpp +#include +#include + +using namespace std; + +int main(){ + int N, K; + cin >> N >> K;// we suppose N > K here and do nothing for unexpected input + int A[N]; + for(int i = 0; i <= N-1; i++){ + cin >> A[i]; + } + priority_queue heap;// we omit two other paras because we just use max heap + for(int i = 0; i <= K-1; i++){ + heap.push(A[i]); + } + for(int i = K; i <= N-1; i++){ + if(A[i] < heap.top()){ + heap.pop(); + heap.push(A[i]); + } + } + while(!heap.empty()){ + cout << heap.top(); + heap.pop(); + } + return; +} +``` -**Find Number occurs half times**([Back to Index](#AnchorIndex)) @@ -270,8 +308,8 @@ int MoreThanHalf(int a[], int N) return candidate; } ``` - --**[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/)**(#AnchorIndex)) + +-**[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/)**([Back to Index](#AnchorIndex)) 每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代,这样每次能去除掉一半的元素,时间复杂度为O(log(m+n))。 ```java class Solution { From b02870487069d2b59e33d05f144fc5b157d093b2 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 09:49:23 +0800 Subject: [PATCH 265/327] add seperators --- Array & String.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Array & String.md b/Array & String.md index ef99902..6c5a421 100644 --- a/Array & String.md +++ b/Array & String.md @@ -7,6 +7,7 @@ Index: -[Find Number occurs half times](#Anchor4) -[Leetcode:Median of Two Sorted Arrays](#Anchor5) +------- -**[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/)**([Back to Index](#AnchorIndex)) @@ -110,6 +111,7 @@ vector twoSingleNumber(int A[], int n){ ``` singleNumberSpecial()先找到两个数字不同的bit位,然后利用该bit位将数组分成两组,再应用之前的方法求解。 +------- -**Find Reverse Pair**([Back to Index](#AnchorIndex)) 问题描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 @@ -174,6 +176,7 @@ public class Main { } ``` +------- -**Find Min K**([Back to Index](#AnchorIndex)) 问题描述:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 @@ -273,6 +276,7 @@ int main(){ } ``` +------- -**Find Number occurs half times**([Back to Index](#AnchorIndex)) 问题描述:找出出现次数刚好是一半的数字。有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。 @@ -308,6 +312,8 @@ int MoreThanHalf(int a[], int N) return candidate; } ``` + +------- -**[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/)**([Back to Index](#AnchorIndex)) 每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代,这样每次能去除掉一半的元素,时间复杂度为O(log(m+n))。 From bf3799485cb6d12189661bcb4d1e3cfed017b59f Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 10:06:14 +0800 Subject: [PATCH 266/327] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a287ff2..d51b3f7 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ Chapters 1. Website construction ####Basic Knowledge -1. [Basic Java Concepts](Basic Java Concepts.md) +1. [Basic Java Concepts](Basic Java Concepts.md) +2. [NIO](NIO.md) Core contributors ------------ From c752cf04b887afd6f6619dc4d271abb734f8ba22 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 10:07:49 +0800 Subject: [PATCH 267/327] Create NIO.md --- NIO.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 NIO.md diff --git a/NIO.md b/NIO.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/NIO.md @@ -0,0 +1 @@ +NULL From 168d71cafbf37dc66cba888ef637deaf133c880e Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 11:54:49 +0800 Subject: [PATCH 268/327] Create Stack.md --- Stack.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Stack.md diff --git a/Stack.md b/Stack.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Stack.md @@ -0,0 +1 @@ +NULL From 0b693b8c3c73867b26182aa976651c6ddb5e104d Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 11:55:28 +0800 Subject: [PATCH 269/327] Create Geometry.md --- Geometry.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Geometry.md diff --git a/Geometry.md b/Geometry.md new file mode 100644 index 0000000..7951def --- /dev/null +++ b/Geometry.md @@ -0,0 +1 @@ +NULL From b94749d1eecaa2476353b1e0e6a6372fad6b79c2 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 11:56:57 +0800 Subject: [PATCH 270/327] add stack and geometry --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d51b3f7..9517e7a 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,10 @@ Chapters 3. [Greedy Strategy](Greedy Strategy.md) 4. [Tree & Linkedlist](Tree & Linkedlist.md) 5. [BFS & DFS](BFS & DFS.md) -6. [STL related](STL related.md) -7. [Others](Others.md) +6. [Stack](Stack.md) +7. [Geometry](Geometry.md) +8. [STL related](STL related.md) +9. [Others](Others.md) ####Engineering 1. Website construction From fe346b5d9fa4a13267d95830e7b2dafd59f1299f Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:00:13 +0800 Subject: [PATCH 271/327] Update 4.Search Array$keywords search.md --- 4.Search Array$keywords search.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index a4acfba..fde7efd 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -1,7 +1,7 @@ #4.Search Array$keywords:search ##*Search array -Ex1:[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/) +Ex1:[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/)[Removed] 两个变量,ones和twos,顺序遍历并且求出异或值,ones表示异或值哪些位 比特1出现一次,twos表示异或值哪些位 比特1出现两次,当异或值的某些位 比特1出现三次的时候,就要对其进行清除,这样就能保证最后得到的ones就是出现一次的数 ```java @@ -211,7 +211,7 @@ public class Main { } ``` -Ex4:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 +Ex4:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。[Removed] 在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组 另:该题也可以用Ex7堆排序实现 @@ -332,7 +332,7 @@ public class MyOwn { } ``` -Ex6:加强版水王,找出出现次数刚好是一半的数字:有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。 +Ex6:加强版水王,找出出现次数刚好是一半的数字:有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。[Removed] 首先,水王占总数的一半,说明总数必为偶数;其次,最后一个元素或者是水王,或者不是水王,因此只要在扫描数组的时候每一个元素都与最后一个元素做比较,如果相等则最后一个元素的个数加1,否则不处理。如果最后一个元素的个数为N/2,(N为数组元素个数)则它就是水王,否则水王就是前面N-1个元素中选出的candidate。 ```cpp @@ -367,7 +367,7 @@ int MoreThanHalf(int a[], int N) } ``` -Ex7:堆排序:写出一个堆排序算法,对数组排序 +Ex7:堆排序:写出一个堆排序算法,对数组排序 [Deprecated] 之所以把堆排序算在搜索里面,是因为很多时候在大数据中查找的时候,会用到堆排序。堆排序的思想就是首先建立一个大根堆,然后将堆顶和数组的最后一个元素交换,之后维护大根堆,然后再交换,如此循环。 ```java public class MyOwn { @@ -418,7 +418,7 @@ public class MyOwn { } ``` -Ex8:[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) +Ex8:[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) [Removed] 每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代 ```java class Solution { From bc3028a57045eda0a0d3a3ff5e31b2178e67c299 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:01:00 +0800 Subject: [PATCH 272/327] Update 4.Search Array$keywords search.md --- 4.Search Array$keywords search.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index fde7efd..3da953e 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -332,8 +332,7 @@ public class MyOwn { } ``` -Ex6:加强版水王,找出出现次数刚好是一半的数字:有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。[Removed] - +Ex6:加强版水王,找出出现次数刚好是一半的数字:有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。[Removed] 首先,水王占总数的一半,说明总数必为偶数;其次,最后一个元素或者是水王,或者不是水王,因此只要在扫描数组的时候每一个元素都与最后一个元素做比较,如果相等则最后一个元素的个数加1,否则不处理。如果最后一个元素的个数为N/2,(N为数组元素个数)则它就是水王,否则水王就是前面N-1个元素中选出的candidate。 ```cpp int MoreThanHalf(int a[], int N) From f2475e3d6a761b2f60747a933a4d8f05e51100b5 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:01:32 +0800 Subject: [PATCH 273/327] Update 4.Search Array$keywords search.md --- 4.Search Array$keywords search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 3da953e..35b8e61 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -366,7 +366,7 @@ int MoreThanHalf(int a[], int N) } ``` -Ex7:堆排序:写出一个堆排序算法,对数组排序 [Deprecated] +Ex7:堆排序:写出一个堆排序算法,对数组排序 [Deprecated] 之所以把堆排序算在搜索里面,是因为很多时候在大数据中查找的时候,会用到堆排序。堆排序的思想就是首先建立一个大根堆,然后将堆顶和数组的最后一个元素交换,之后维护大根堆,然后再交换,如此循环。 ```java public class MyOwn { From 9b07ccaac8b31bc79334e0ca3bc0bc7fd5a3505f Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:02:00 +0800 Subject: [PATCH 274/327] Update 4.Search Array$keywords search.md --- 4.Search Array$keywords search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index 35b8e61..d29752e 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -417,7 +417,7 @@ public class MyOwn { } ``` -Ex8:[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) [Removed] +Ex8:[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) [Removed] 每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代 ```java class Solution { From 61e3d3f1d411d017ab9a0f837e97acc478ba2236 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:15:13 +0800 Subject: [PATCH 275/327] Update NIO.md --- NIO.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/NIO.md b/NIO.md index 7951def..25569cc 100644 --- a/NIO.md +++ b/NIO.md @@ -1 +1,49 @@ -NULL +##NIO +本章翻译和总结自DevelopWorks的《Getting started with NIO》,介绍了Java NIO的主要原理。如有谬误,请发送pull request。 + +Index: +-[1.为什么要使用NIO](#Anchor1) +-[2.NIO和传统IO的区别?](#Anchor2) +-[3.Channels和Buffers](#Anchor3) +-[4.如何分配Buffer,生成文件的管道,通过管道做文件IO?](#Anchor4) +-[5.Buffer的内部实现](#Anchor5) +-[6.分发和收集式NIO](#Anchor6) +-[7.文件锁](#Anchor7) +-[8.网络和异步I/O](#Anchor8) +-[9.字符集](#Anchor9) + +------- + +-**1.为什么要使用NIO**([Back to Index](#AnchorIndex)) + +------- + +-**2.NIO和传统IO的区别?**([Back to Index](#AnchorIndex)) + +------- + +-**3.Channels和Buffers**([Back to Index](#AnchorIndex)) + +------- + +-**4.如何分配Buffer,生成文件的管道,通过管道做文件IO?**([Back to Index](#AnchorIndex)) + +------- + +-**5.Buffer的内部实现**([Back to Index](#AnchorIndex)) + +------- + +-**6.分发和收集式NIO**([Back to Index](#AnchorIndex)) + +------- + +-**7.文件锁**([Back to Index](#AnchorIndex)) + +------- + +-**8.网络和异步I/O**([Back to Index](#AnchorIndex)) + +------- + +-**9.字符集**([Back to Index](#AnchorIndex)) From bb3ade85d323f029c097ae2ffbb23545854d3570 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:15:51 +0800 Subject: [PATCH 276/327] Update NIO.md --- NIO.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/NIO.md b/NIO.md index 25569cc..03aefd5 100644 --- a/NIO.md +++ b/NIO.md @@ -1,16 +1,16 @@ ##NIO -本章翻译和总结自DevelopWorks的《Getting started with NIO》,介绍了Java NIO的主要原理。如有谬误,请发送pull request。 +本章翻译和总结自DevelopWorks的《Getting started with NIO》,介绍了Java NIO的主要原理。如有谬误,请发送pull request。 Index: -[1.为什么要使用NIO](#Anchor1) -[2.NIO和传统IO的区别?](#Anchor2) -[3.Channels和Buffers](#Anchor3) -[4.如何分配Buffer,生成文件的管道,通过管道做文件IO?](#Anchor4) --[5.Buffer的内部实现](#Anchor5) --[6.分发和收集式NIO](#Anchor6) --[7.文件锁](#Anchor7) --[8.网络和异步I/O](#Anchor8) --[9.字符集](#Anchor9) +-[5.Buffer的内部实现](#Anchor5) +-[6.分发和收集式NIO](#Anchor6) +-[7.文件锁](#Anchor7) +-[8.网络和异步I/O](#Anchor8) +-[9.字符集](#Anchor9) ------- From 90d70066148048aeb8c89e750c2b241f3255aced Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:35:52 +0800 Subject: [PATCH 277/327] need a picture --- NIO.md | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/NIO.md b/NIO.md index 03aefd5..f94b7b9 100644 --- a/NIO.md +++ b/NIO.md @@ -15,35 +15,140 @@ Index: ------- -**1.为什么要使用NIO**([Back to Index](#AnchorIndex)) +NIO把最耗费时间的IO行为转移到了操作系统因此提高了IO速度。 ------- -**2.NIO和传统IO的区别?**([Back to Index](#AnchorIndex)) +两者最重要的区别是如何封装数据和传输数据。 + + * 传统IO:面向流,IO系统每次处理一个字节 + * NIO:面向块,IO系统每次处理一块数据 + +但现在的传统IO也有使用NIO的优良特性来优化自身的性能;使用NIO也可以很容的实现传统IO,——只要每次读写一个字节即可。 ------- -**3.Channels和Buffers**([Back to Index](#AnchorIndex)) +Channel和Buffer是NIO的核心类。传统IO使用两个Stream对象做对接,不经过中间介质;而NIO使用Buffer作为缓冲区,Channel的读写行为都发生在Buffer上,而不是另一个Channel上。 + +Buffer主要为Channel提供数据缓冲,但也提供直接对其内容操作的方法。Buffer追踪系统的读写进度。对于每个Java原语类型都有其对应的Buffer派生类,如ByteBuffer、CharBuffer和ShortBuffer等 + +Channel是为用户提供读写操作的对象,作用类似传统IO中的Stream对象,但Channel是双向的(可以从Buffer读或写)而Stream是单向的(需要把一个输入流和输出流关联起来) ------- -**4.如何分配Buffer,生成文件的管道,通过管道做文件IO?**([Back to Index](#AnchorIndex)) +ByteBuffer buffer = ByteBuffer.allocate(1024);//生成Buffer +FileInputStream fin = new FileInputStream("input.txt");//生成输入流对象 +FileChannel fcin = fin.getChannel();//从输入流获取管道对象 +FileOutputStream fout = new FileOutputStream("output.txt");//生成输出流对象 +FileChannel fcout = fout.getChannel();//从输出流获取管道对象 + +典型的buffer读写代码片段如下所示: +```java +while(true){ + buffer.clear();//将position置为0,将limit置为buffer.capacity + int r = fcin.read(buffer);//写buffer + if(r = -1){ + break; + } + buffer.flip();//将position置为0,将limit置为之前position的值 + fcout.write(buffer);//读buffer +} +``` ------- -**5.Buffer的内部实现**([Back to Index](#AnchorIndex)) + * 状态变量 + * position:指向有效数据区的尾部 + * limit:总是小于等于capacity,在读的情况下指向有效数据区的尾部,在写的情况下指向缓冲区的尾部 + * capacity:缓冲区的最大容量 + + * clear()和flip()方法: + * clear()使得position回到0,limit指向缓冲区尾部,为read(写)做准备 + * flip()使得position回到0,limit指向有效数据区的尾部,为write(读)做准备 + + * get()和put()方法 + * 无论get还是put方法都分为绝对方法(指定了绝对位置)和相对方法,返回的ByteBuffer对象均为发生本次调用的对象自身 + * get()方法有四种形式 + * byte get(); + * ByteBuffer get(byte dst[]); + * ByteBuffer get(byte dst[], int offset, int length); + * byte get(int index); + + * put()方法有五种形式 + * ByteBuffer put(byte b); + * ByteBuffer put(byte src[]); + * ByteBuffer put(byte src[], int offset, int length); + * ByteBuffer put(ByteBuffer src); + * ByteBuffer put(int index, byte b); + + * get和put方法针对每种原语类型也有不同的实现 + + * Direct Buffer,该缓冲区并不存在与堆上,使用native方法提高IO速度 + * Buffer对象生成方法 + * allocate(int size);//分配指定大小的Buffer + * wrap(byte array[]);//将字节数组转换为Buffer + * slice();//以当前的position为头,limit为尾切分出子Buffer,注意,子Buffer与原Buffer共享底层数据 + * asReadOnlyBuffer();//生成一个只读Buffer,只读Buffer不能被转换为可写Buffer + * Memory-mapped file I/O,可以生成一个内存映射文件Buffer对象,避免对内存的读写而直接进行IO操作,提高了效率,但可能会有不安全因素 + * MappedByteBuffer mbb = fc. map(FileChannel.MapMode.READ_WRITE,0,1024); + ------- -**6.分发和收集式NIO**([Back to Index](#AnchorIndex)) +分发和收集式NIO利用两个Channel和一组Buffer实现数据的传输,具体实现方式是使用Channel的read(Buffer[])和write(Buffer[]),在read(写)时会顺序选择第一个可用的(剩余容量大于要写入块大小)的Buffer进行。应用场景如使用两个Buffer,一个Buffer为消息的header大小,另一个Buffer为消息的body大小,这样就能很自然的将两者分开读取。 ------- -**7.文件锁**([Back to Index](#AnchorIndex)) +文件锁的并不是用来阻止其他进程/线程对文件的访问,而是通过文件锁机制来实现系统不同部分的协调运转。通常可以为整个或部分文件加锁,文件锁分为互斥锁(exclusive lock)和共享锁(shared lock),一个获取文件锁的操作示例如下: +```java +RandomAccessFile raf = new RandomAccessFile("usefilelocks.txt","rw");//互斥锁要求必须打开w选项(因为写互斥是OS支持的) +FileChannel fc = raf.getChannel(); +FileLock lock = fc.lock(start,end,false); +// ... +lock.release();//释放锁 +``` +文件锁需要谨慎使用,使用建议: + + * 只使用互斥锁 + * 将锁看做是建议性的 ------- -**8.网络和异步I/O**([Back to Index](#AnchorIndex)) +异步I/O实现了数据的无阻塞读写操作,其核心类包括Selector,ServerSocketChannel,SocketChannel和SelectionKey以及ByteBuffer。 + +[piclink] + +如下github链接是一个典型的NIO实现 + `https://github.com/yangwm/JavaLearn/blob/master/src/jnio/MultiPortEcho.java` + +可用的注册事件名和对应值 + + * 服务端接收客户端连接事件 SelectionKey.OP_ACCEPT(16) + * 客户端连接服务端事件 SelectionKey.OP_CONNECT(8) + * 读事件 SelectionKey.OP_READ(1) + * 写事件 SelectionKey.OP_WRITE(4) + +在实际应用中,可能需要将Channel从Selector的注册表中移出,同时使用多线程来处理收到的数 + +NIO比BIO的在某些情况下还更差一些,因为这里需要使用两个system call (select 和 recvfrom),而BIO只调用了一个system call (recvfrom)。但是,用select的优势在于它可以同时处理多个连接。所以如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。 ------- -**9.字符集**([Back to Index](#AnchorIndex)) +使用CharsetDecoder和CharsetEncoder可以在CharBuffer和ByteBuffer之间做转换,如: +```java +Charset latin1 = Charset.forName("ISO-8859-1"); +CharsetDecoder decoder = latin1.newDecoder(); +CharsetEncoder encoder = latin1.newEncoder(); +ByteBuffer inputData; +CharBuffer cb = decoder.decode(inputData); +ByteBuffer outputData = encoder.encode(cb); +``` + From 5dd5ff5c98603c4bc2386c81d440995a05148644 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Sat, 25 Oct 2014 12:38:41 +0800 Subject: [PATCH 278/327] Update NIO.md --- NIO.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NIO.md b/NIO.md index f94b7b9..9a77c0e 100644 --- a/NIO.md +++ b/NIO.md @@ -39,11 +39,13 @@ Channel是为用户提供读写操作的对象,作用类似传统IO中的Strea ------- -**4.如何分配Buffer,生成文件的管道,通过管道做文件IO?**([Back to Index](#AnchorIndex)) +```java ByteBuffer buffer = ByteBuffer.allocate(1024);//生成Buffer FileInputStream fin = new FileInputStream("input.txt");//生成输入流对象 FileChannel fcin = fin.getChannel();//从输入流获取管道对象 FileOutputStream fout = new FileOutputStream("output.txt");//生成输出流对象 FileChannel fcout = fout.getChannel();//从输出流获取管道对象 +``` 典型的buffer读写代码片段如下所示: ```java @@ -123,6 +125,7 @@ lock.release();//释放锁 -**8.网络和异步I/O**([Back to Index](#AnchorIndex)) 异步I/O实现了数据的无阻塞读写操作,其核心类包括Selector,ServerSocketChannel,SocketChannel和SelectionKey以及ByteBuffer。 +下图展示了NIO典型工作过程 [piclink] 如下github链接是一个典型的NIO实现 From 0d8279a3d2abe62f693c08cee38421fc724761f8 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Sat, 25 Oct 2014 12:43:52 +0800 Subject: [PATCH 279/327] add NIO working process picture --- Image/NIO working process.png | Bin 0 -> 31976 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Image/NIO working process.png diff --git a/Image/NIO working process.png b/Image/NIO working process.png new file mode 100644 index 0000000000000000000000000000000000000000..59dd24a5f3aceb50e32fcd1453acfa147559af8e GIT binary patch literal 31976 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%0Dt}cZ-G~%XMqUy_XADO1zEow1HYhW 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 Date: Sat, 25 Oct 2014 12:48:30 +0800 Subject: [PATCH 280/327] add NIO working process picture --- NIO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NIO.md b/NIO.md index 9a77c0e..4da9f69 100644 --- a/NIO.md +++ b/NIO.md @@ -126,7 +126,8 @@ lock.release();//释放锁 异步I/O实现了数据的无阻塞读写操作,其核心类包括Selector,ServerSocketChannel,SocketChannel和SelectionKey以及ByteBuffer。 下图展示了NIO典型工作过程 -[piclink] + +![NIO working process](Image/NIO working process.png "NIO working process") 如下github链接是一个典型的NIO实现 `https://github.com/yangwm/JavaLearn/blob/master/src/jnio/MultiPortEcho.java` From 50c98d043d09ad2162457cc6a608fa11c5f092d2 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 10:20:10 +0800 Subject: [PATCH 281/327] Update Dynamic Programming.md --- Dynamic Programming.md | 62 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 7951def..0346044 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -1 +1,61 @@ -NULL +##Dynamic Programming + +Index: +-[Leetcode:Best Time to Buy and Sell Stock III](#Anchor1) +-[](#Anchor2) +-[](#Anchor3) +-[](#Anchor4) +-[](#Anchor5) + +------- + +-**[Leetcode:Best Time to Buy and Sell Stock III](http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/)**([Back to Index](#AnchorIndex)) + +分别记录到i时,0-i的最大利润和i+1到len-1的最大利润,相加即可。具体做法是 + * 使用forwardMax[i]记录0到i的最大利润(正向) + * 使用backwardMax[i]记录n-1到i的最大利润(反向) +```java +public class Solution { + public int maxProfit(int[] prices) { + if (prices == null || prices.length < 2) return 0; + int[] forwardMax = new int[prices.length]; + int[] backwardMax = new int[prices.length]; + + int buyPoint = prices[0]; + int sellPoint = prices[0]; + int maxProfit = 0; + forwardMax[0] = 0; + + for (int i = 1; i < prices.length; i++) { + if (prices[i] < buyPoint) { + buyPoint = prices[i]; + } + forwardMax[i] = Math.max(prices[i] - buyPoint, forwardMax[i - 1]); + } + sellPoint = prices[prices.length - 1]; + backwardMax[prices.length - 1] = 0; + + for (int i = prices.length - 2; i >= 0; i--) { + if (prices[i] > sellPoint) { + sellPoint = prices[i]; + } + backwardMax[i] = Math.max(sellPoint - prices[i], backwardMax[i + 1]); + } + + int max = 0; + for (int i = 0; i < prices.length - 1; i++) { + if (forwardMax[i] + backwardMax[i + 1] > max) { + max = forwardMax[i] + backwardMax[i + 1]; + } + } + if (max < Math.max(forwardMax[prices.length - 1], backwardMax[0])) { + max = Math.max(forwardMax[prices.length - 1], backwardMax[0]); + } + return max; + } +} +``` + +------- + +-****([Back to Index](#AnchorIndex)) From 4f87997043013c4b57cc0abf0c370d8738a7801e Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 10:23:27 +0800 Subject: [PATCH 282/327] Update 4.Search Array$keywords search.md --- 4.Search Array$keywords search.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md index d29752e..96ee500 100644 --- a/4.Search Array$keywords search.md +++ b/4.Search Array$keywords search.md @@ -103,7 +103,7 @@ vector twoSingleNumber(int A[], int n){ ``` singleNumberSpecial()先找到两个数字不同的bit位,然后利用该bit位将数组分成两组,再应用之前的方法求解。 -Ex2:[Leetcode:Best Time to Buy and Sell Stock III](http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/) +Ex2:[Leetcode:Best Time to Buy and Sell Stock III](http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/)(Removed) 分别记录到i时,0-i的最大利润和i+1到len-1的最大利润,相加即可。 ```java @@ -148,7 +148,7 @@ public class Solution { } ``` -Ex3:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 +Ex3:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。(Removed) 使用普通的比较时间复杂度是n方。这里介绍一种复杂度为nlogn的方法。该方法要借助归并排序,即将数组分为两部分分别排序,然后merge。之后在对两个子数组进行merge的时候,去比较子数组1的当前元素和子数组2的当前元素,若1大于2,则说明1后面的元素都大于2,所以都为逆序对,将这些数加入结果集。 ```java @@ -268,7 +268,7 @@ int main() } ``` -Ex5:任意给定一个正整数N,求一个最小的M(M>1),使得N*M的十进制表示形式里只含有1和0。 +Ex5:任意给定一个正整数N,求一个最小的M(M>1),使得N*M的十进制表示形式里只含有1和0。(Removed) 首先我们要维护一个余数信息数组,里面存放的是满足表示形式为1和0的,求余N为j的最小的数。若10的i次幂求余N等于j的话,就将这个数加入余数数组。然后遍历已经存在的余数信息数组。假设10的p次幂求余N等于k,则(10的p次幂+10的i次幂)% N =(j+k)%N,所以将余数为k的数和余数为j的数加入余数为(j+k)的数组中。下面是解决这道题的算法,想要看懂该算法需要明白两个条件:(1)(x*10)% N = (x%N*10)% N (2)在一轮N次更新后,如果余数数组没有出现更新,那么将进入死循环,不再有结果,退出 ```java From cc0caf1396019b3a15d446adfd172c9a5c2dd757 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 10:26:24 +0800 Subject: [PATCH 283/327] Update Others.md --- Others.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/Others.md b/Others.md index 7951def..70f8fd4 100644 --- a/Others.md +++ b/Others.md @@ -1 +1,73 @@ -NULL +##Others + +Index: +-[Find the number(not exceeding M) only formed by 0 and 1](#Anchor1) +-[](#Anchor2) +-[](#Anchor3) +-[](#Anchor4) +-[](#Anchor5) + +------- + +-**Find the number(not exceeding M) only formed by 0 and 1**([Back to Index](#AnchorIndex)) +首先我们要维护一个余数信息数组,里面存放的是满足表示形式为1和0的,求余N为j的最小的数。若10的i次幂求余N等于j的话,就将这个数加入余数数组。然后遍历已经存在的余数信息数组。假设10的p次幂求余N等于k,则(10的p次幂+10的i次幂)% N =(j+k)%N,所以将余数为k的数和余数为j的数加入余数为(j+k)的数组中。下面是解决这道题的算法,想要看懂该算法需要明白两个条件:(1)(x*10)% N = (x%N*10)% N (2)在一轮N次更新后,如果余数数组没有出现更新,那么将进入死循环,不再有结果,退出 +```java +import java.util.ArrayList; + +public class MyOwn { + public void Only10(int N) { + ArrayList> b = new ArrayList>(); + for (int i = 0; i < N; i++) + b.add(new ArrayList()); + b.get(1).add(0); + int noUpdate = 0; + + for (int i = 1, j = 10 % N;; i++, j = (j * 10) % N) { + boolean flag = false; + if (b.get(j).size() == 0) { + flag = true; + b.get(j).add(i); + } + for (int k = 1; k < N; k++) { + if (b.get(k).size() > 0 + && i > b.get(k).get(b.get(k).size() - 1) + && b.get((j + k) % N).size() == 0) { + flag = true; + b.set((j + k) % N, b.get(k)); + b.get((j + k) % N).add(i); + } + } + + if (flag) + noUpdate = 0; + else + noUpdate++; + + if (noUpdate == N || b.get(0).size() > 0) + break; + } + + if (noUpdate == N) + System.out.println("Not Exit"); + else { + int max = b.get(0).get(b.get(0).size() - 1); + long result = 0; + for (int i = max; i >= 0; i--) { + if (b.get(0).contains(i)) + result = result * 10 + 1; + else + result = result * 10; + } + // if (b.get(0).get(0) == 0) + // result = result * 10; + System.out.println("result: " + result); + System.out.println("N: " + N + " M: " + result / N); + } + } + + public static void main(String[] args) { + MyOwn m = new MyOwn(); + m.Only10(24); + } +} +``` From b6f2066b1cc68e165a9661777d4e7c82262dfec2 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 10:27:29 +0800 Subject: [PATCH 284/327] Delete 4.Search Array$keywords search.md --- 4.Search Array$keywords search.md | 451 ------------------------------ 1 file changed, 451 deletions(-) delete mode 100644 4.Search Array$keywords search.md diff --git a/4.Search Array$keywords search.md b/4.Search Array$keywords search.md deleted file mode 100644 index 96ee500..0000000 --- a/4.Search Array$keywords search.md +++ /dev/null @@ -1,451 +0,0 @@ -#4.Search Array$keywords:search -##*Search array - -Ex1:[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/)[Removed] - -两个变量,ones和twos,顺序遍历并且求出异或值,ones表示异或值哪些位 比特1出现一次,twos表示异或值哪些位 比特1出现两次,当异或值的某些位 比特1出现三次的时候,就要对其进行清除,这样就能保证最后得到的ones就是出现一次的数 -```java -public class Solution { - public int singleNumber(int[] A) { - int one = 0, two = 0, erase = 0; - for (int i = 0; i < A.length; i++) { - two |= one & A[i]; - one ^= A[i]; - erase = ~(one & two); - two &= erase; - one &= erase; - } - - return one; - } -} -``` -另外一个更直观更通用的解法是模拟法,但此种解法在OJ上可能超时。如下: -```cpp -#define ARY 3 - -int singleNumber(int A[], int n){ - int ret = 0; - int count[32]; - memset(count,0,sizeof(count)); - for(int i = 0; i <= 31; i++){ - int b = 1 << i; - for(int j = 0; j <= n-1; j++){ - if(A[j] & b){ - count[i]++; - } - } - if(count[i]%ARY){ - ret |= b; - } - } - return ret; -} -``` -在解决复杂同类问题时,这种方法更显得直观,如一组数据中出现两个不同的数字各一次(或k次),其余均出现a次,求出那两个数字,代码如下: -```cpp -int singleNumber(int A[], int n){ - int ret = 0; - int count[32]; - memset(count,0,sizeof(count)); - for(int i = 0; i <= 31; i++){ - int b = 1 << i; - for(int j = 0; j <= n-1; j++){ - if(A[j] & b){ - count[i]++; - } - } - if(count[i]%ARY){ - ret |= b; - } - } - return ret; -} - -int singleNumberSpecial(int A[], int n){ - int ret = 0; - int count[32]; - memset(count,0,sizeof(count)); - for(int i = 0; i <= 31; i++){ - int b = 1 << i; - for(int j = 0; j <= n-1; j++){ - if(A[j] & b){ - count[i]++; - } - } - if(count[i]%ARY == 1){ - ret |= b; - } - } - return ret; -} - -vector twoSingleNumber(int A[], int n){ - int twoNum = singleNumberSpecial(A, n); - int b = twoNum & (-twoNum); - int B[n],C[n]; - int bi = 0,ci = 0; - int single1 = 0, single2 = 0; - for(int i = 0; i <= n-1; i++){ - if(A[i] & b){ - B[bi++] = A[i]; - }else{ - C[ci++] = A[i]; - } - } - single1 = singleNumber(B, bi); - single2 = singleNumber(C, ci); - vector vec; - vec.push_back(single1); - vec.push_back(single2); - return vec; -} -``` -singleNumberSpecial()先找到两个数字不同的bit位,然后利用该bit位将数组分成两组,再应用之前的方法求解。 - -Ex2:[Leetcode:Best Time to Buy and Sell Stock III](http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/)(Removed) - -分别记录到i时,0-i的最大利润和i+1到len-1的最大利润,相加即可。 -```java -public class Solution { - public int maxProfit(int[] prices) { - if (prices == null || prices.length < 2) return 0; - int[] forwardMax = new int[prices.length]; - int[] backwardMax = new int[prices.length]; - - int buyPoint = prices[0]; - int sellPoint = prices[0]; - int maxProfit = 0; - forwardMax[0] = 0; - - for (int i = 1; i < prices.length; i++) { - if (prices[i] < buyPoint) { - buyPoint = prices[i]; - } - forwardMax[i] = Math.max(prices[i] - buyPoint, forwardMax[i - 1]); - } - sellPoint = prices[prices.length - 1]; - backwardMax[prices.length - 1] = 0; - - for (int i = prices.length - 2; i >= 0; i--) { - if (prices[i] > sellPoint) { - sellPoint = prices[i]; - } - backwardMax[i] = Math.max(sellPoint - prices[i], backwardMax[i + 1]); - } - - int max = 0; - for (int i = 0; i < prices.length - 1; i++) { - if (forwardMax[i] + backwardMax[i + 1] > max) { - max = forwardMax[i] + backwardMax[i + 1]; - } - } - if (max < Math.max(forwardMax[prices.length - 1], backwardMax[0])) { - max = Math.max(forwardMax[prices.length - 1], backwardMax[0]); - } - return max; - } -} -``` - -Ex3:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。(Removed) - -使用普通的比较时间复杂度是n方。这里介绍一种复杂度为nlogn的方法。该方法要借助归并排序,即将数组分为两部分分别排序,然后merge。之后在对两个子数组进行merge的时候,去比较子数组1的当前元素和子数组2的当前元素,若1大于2,则说明1后面的元素都大于2,所以都为逆序对,将这些数加入结果集。 -```java -public class Main { - static long count = 0; - - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - while (in.hasNext()) { - int n = in.nextInt(); - int[] a = new int[n]; - for (int i = 0; i < n; i++) - a[i] = in.nextInt(); - count = 0; - mergeSort(a); - System.out.println(count); - } - } - - // 将有二个有序数列a[first...mid]和a[mid...last]合并。 - static void mergearray(int a[], int first, int mid, int last, int temp[]) { - int i = first, j = mid + 1; - int m = mid, n = last; - int k = 0; - while (i <= m && j <= n) { - if (a[i] > a[j]) { - // 左数组比右数组大 - temp[k++] = a[j++]; - // 因为如果a[i]此时比右数组的当前元素a[j]大, - // 那么左数组中a[i]后面的元素就都比a[j]大 - // 【因为数组此时是有序数组】 - count += mid - i + 1; - } else { - temp[k++] = a[i++]; - } - } - while (i <= m) { - temp[k++] = a[i++]; - } - while (j <= n) { - temp[k++] = a[j++]; - } - for (i = 0; i < k; i++) - a[first + i] = temp[i]; - } - - static void mergesort(int a[], int first, int last, int temp[]) { - if (first < last) { - int mid = (first + last) / 2; - mergesort(a, first, mid, temp); // 左边有序 - mergesort(a, mid + 1, last, temp); // 右边有序 - mergearray(a, first, mid, last, temp); // 再将二个有序数列合并 - } - } - - static void mergeSort(int a[]) { - int[] p = new int[a.length]; - mergesort(a, 0, a.length - 1, p); - } -} -``` - -Ex4:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。[Removed] - -在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组 -另:该题也可以用Ex7堆排序实现 - -```cpp -#include -#include -#include -#include -using namespace std; -#define LL long long -void swap(LL *a, LL *b){ - LL tmp=*a; - *a=*b; - *b=tmp; -} - -int partition_arr(int low,int high,LL *arr,const int k){ - if(low>=high) - return 0; - LL tmp=arr[low]; - int i=low,j=high+1; - LL pivot=arr[low]; - while(1){ - while(arr[++i]pivot); - if(i=k){ - printf("%d",arr[0]); - for(i=1;i1),使得N*M的十进制表示形式里只含有1和0。(Removed) - -首先我们要维护一个余数信息数组,里面存放的是满足表示形式为1和0的,求余N为j的最小的数。若10的i次幂求余N等于j的话,就将这个数加入余数数组。然后遍历已经存在的余数信息数组。假设10的p次幂求余N等于k,则(10的p次幂+10的i次幂)% N =(j+k)%N,所以将余数为k的数和余数为j的数加入余数为(j+k)的数组中。下面是解决这道题的算法,想要看懂该算法需要明白两个条件:(1)(x*10)% N = (x%N*10)% N (2)在一轮N次更新后,如果余数数组没有出现更新,那么将进入死循环,不再有结果,退出 -```java -import java.util.ArrayList; - -public class MyOwn { - public void Only10(int N) { - ArrayList> b = new ArrayList>(); - for (int i = 0; i < N; i++) - b.add(new ArrayList()); - b.get(1).add(0); - int noUpdate = 0; - - for (int i = 1, j = 10 % N;; i++, j = (j * 10) % N) { - boolean flag = false; - if (b.get(j).size() == 0) { - flag = true; - b.get(j).add(i); - } - for (int k = 1; k < N; k++) { - if (b.get(k).size() > 0 - && i > b.get(k).get(b.get(k).size() - 1) - && b.get((j + k) % N).size() == 0) { - flag = true; - b.set((j + k) % N, b.get(k)); - b.get((j + k) % N).add(i); - } - } - - if (flag) - noUpdate = 0; - else - noUpdate++; - - if (noUpdate == N || b.get(0).size() > 0) - break; - } - - if (noUpdate == N) - System.out.println("Not Exit"); - else { - int max = b.get(0).get(b.get(0).size() - 1); - long result = 0; - for (int i = max; i >= 0; i--) { - if (b.get(0).contains(i)) - result = result * 10 + 1; - else - result = result * 10; - } - // if (b.get(0).get(0) == 0) - // result = result * 10; - System.out.println("result: " + result); - System.out.println("N: " + N + " M: " + result / N); - } - } - - public static void main(String[] args) { - MyOwn m = new MyOwn(); - m.Only10(24); - } -} -``` - -Ex6:加强版水王,找出出现次数刚好是一半的数字:有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。[Removed] -首先,水王占总数的一半,说明总数必为偶数;其次,最后一个元素或者是水王,或者不是水王,因此只要在扫描数组的时候每一个元素都与最后一个元素做比较,如果相等则最后一个元素的个数加1,否则不处理。如果最后一个元素的个数为N/2,(N为数组元素个数)则它就是水王,否则水王就是前面N-1个元素中选出的candidate。 -```cpp -int MoreThanHalf(int a[], int N) -{ - int sum1 = 0;//最后一个元素的个数 - int sum2 = 0; - int candidate; - int i; - for(i=0;i 0; i--) { - swap(0, i, a); - adjust(1, i, a); - } - } - - public void swap(int i, int j, int[] a) { - int tmp = a[i]; - a[i] = a[j]; - a[j] = tmp; - } - - public void adjust(int i, int max, int[] a) { - int left = 2 * i; - int right = 2 * i + 1; - int big = i; - if (max >= left && a[left - 1] > a[i - 1]) - big = left; - - if (max >= right && a[right - 1] > a[i - 1]) - big = right; - - if (big != i) { - swap(i - 1, big - 1, a); - adjust(big, max, a); - } - } - - public void buildHeap(int[] a) { - int begin = a.length / 2; - // int begin = (int) (Math.floor(a.length / 2)); - for (int i = begin; i >= 1; i--) - adjust(i, a.length, a); - } - - public static void main(String[] args) { - Solution m = new Solution(); - int[] a = { 32, 1, 9, 5, 7, 12, 0, 4 }; - m.heapSort(a); - for (int i : a) - System.out.print(i + " "); - } -} -``` - -Ex8:[Leetcode:Median of Two Sorted Arrays](http://oj.leetcode.com/problems/median-of-two-sorted-arrays/) [Removed] -每次A B数组的k/2位置的元素进行比较,舍弃值较小的数所在数组的前k/2个数,如此迭代 -```java -class Solution { -public: - - double findMedianSortedArrays(int A[], int m, int B[], int n) { - int total = m + n; - if (total & 0x1) - return find_kth(A, m, B, n, total / 2 + 1); - else - return (find_kth(A, m, B, n, total / 2) - + find_kth(A, m, B, n, total / 2 + 1)) / 2; - } -private: - - static double find_kth(int A[], int m, int B[], int n, int k) { - //always assume that m is equal or smaller than n - if (m > n) return find_kth(B, n, A, m, k); - if (m == 0) return B[k - 1]; - if (k == 1) return min(A[0], B[0]); - //divide k into two parts - int pa = min(k / 2, m), pb = k - pa; - if (A[pa - 1] < B[pb - 1]) - return find_kth(A + pa, m - pa, B, n, k - pa); - else if (A[pa - 1] > B[pb - 1]) - return find_kth(A, m, B + pb, n - pb, k - pb); - else - return A[pa - 1]; - } -}; -``` From c8a6548f90b89b958814ee086c594f9cecf90f22 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 10:33:44 +0800 Subject: [PATCH 285/327] Update STL related.md --- STL related.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/STL related.md b/STL related.md index 7951def..71cba3a 100644 --- a/STL related.md +++ b/STL related.md @@ -1 +1,75 @@ -NULL +##STL related + +Index: +-[Heap Sort](#Anchor1) +-[Union Find Sets](#Anchor2) +-[](#Anchor3) +-[](#Anchor4) +-[](#Anchor5) + +------- + +-**Heap Sort**([Back to Index](#AnchorIndex)) + +堆排序算法主要包括建堆和堆调整两大步骤,其中建堆的时间复杂度为O(n),堆调整的总时间复杂度为O(nlogn),因此堆排序的总时间复杂度为O(nlogn),关于该算法的时间复杂度分析证明可查阅相关资料。 + +```cpp +#include + +using namespace std; + +void heapSort(int A[], int len); +void buildHeap(int A[], int len); +void adjust(int A[], int i, int max); +void swap(int * a, int * b); + +int main(){ + int A[7] = {1,3,4,2,7,5,6}; + heapSort(A, 7); + for(int i = 0; i <= 6; i++){ + cout << A[i] << " "; + } +} + +void heapSort(int A[], int len){ + buildHeap(A,len); + for(int i = len-1; i >= 0; i--){ + swap(&A[0], &A[i]); + adjust(A, 1, i); + } +} + +void buildHeap(int A[], int len){ + for(int i = len/2; i >= 1; i--){ + adjust(A, i, len); + } +} + +void adjust(int A[], int i, int max){ + int left = 2 * i; + int right = 2 * i + 1; + int maxIndex = i; + if(left <= max&&A[maxIndex-1] < A[left-1]){ + maxIndex = left; + } + if(right <= max&&A[maxIndex-1] < A[right-1]){ + maxIndex = right; + } + if(maxIndex != i){ + swap(&A[maxIndex-1], &A[i-1]); + adjust(A, maxIndex, max); + } +} + +void swap(int * a, int * b){ + if(*a != *b){ + *a ^= *b; + *b ^= *a; + *a ^= *b; + } +} +``` + +------- + +-**Union Find Sets**([Back to Index](#AnchorIndex)) From 6bd37d2ee26fa50cd0a3c20e2dec320e2538d006 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 11:08:29 +0800 Subject: [PATCH 286/327] Update and rename 14.Probability.md to Probability.md --- 14.Probability.md | 79 ----------------------------- Probability.md | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 79 deletions(-) delete mode 100644 14.Probability.md create mode 100644 Probability.md diff --git a/14.Probability.md b/14.Probability.md deleted file mode 100644 index 6a04a95..0000000 --- a/14.Probability.md +++ /dev/null @@ -1,79 +0,0 @@ -##Probability - -本章收录了一些概率相关问题。 - -Ex1:已知元素个数n,按顺序等概率的选出m个元素(m= 1 && r <= k){ - pick[r-1] = i+1; - } - } -} -``` -1号结点被选取的概率,遍历到1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N -2号结点被选取的概率,遍历到2号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N -k+1号结点被选取的概率,遍历到k+1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N -最后一个结点被选取的概率,遍历到N号结点时被选中:K/N -从1~N依次计算每个i被最终选取的概率,发现都是K/N。 - -Ex3:等概率随机排列数组(洗牌算法) -假设有一个数组,包含n个元素。现在要重新排列这些元素,要求每个元素被放到任何一个位置的概率都相等(即1/n),并且直接在数组上重排(in place),不要生成新的数组。用O(n) 时间、O(1)辅助空间。 -先想想如果可以开辟另外一块长度为n的辅助空间时该怎么处理,显然只要对n个元素做n次(不放回的)随机抽取就可以了。先从n个元素中任选一个,放入新空间的第一个位置,然后再从剩下的n-1个元素中任选一个,放入第二个位置,依此类推。 -按照同样的方法,但这次不开辟新的存储空间。第一次被选中的元素就要放入这个数组的第一个位置,但这个位置原来已经有别的(也可能就是这个)元素了,这时候只要把原来的元素跟被选中的元素互换一下就可以了。很容易就避免了辅助空间 - -Ex4:利用等概率函数Rand5产生等概率函数Rand3 -```cpp -int Rand3(){ - int x; - do{ - x = Rand5(); - }while(x >= 3); - return x;//0,2,1 -} -``` -只要保证返回的3个数是等概率的即可,每个数的概率都为1/5 - -Ex5:利用等概率函数Rand5产生等概率函数Rand7 -```cpp -int Rand7(){ - int x; - do{ - x = Rand()5*5+Rand5(); - }while(x >= 7); - return x; -} -``` -先生成一个比目标大的概率函数,然后在采用之前的方法即可。在生成较大的目标概率函数时,可以使用RandA()*B+RandB()的形式,可保证不重不漏,且每个数产生的概率相同。 - -更一般化的:于已知的RandX()函数,可以使用模拟X进制生成一个比目标大的概率函数,如 -- X^3RandX()+X^2RandX()+XRandX()+RandX() - -可以保证不重不漏,因而能等概率的生成数字 -- pi=n−1n×n−2n−1×⋯×n−i+1n−i+2×1n−i+1=1n - - diff --git a/Probability.md b/Probability.md new file mode 100644 index 0000000..ee87e06 --- /dev/null +++ b/Probability.md @@ -0,0 +1,125 @@ +##Array & String + +Index: +-[Select m elems from n equiprobably](#Anchor1) +-[Select k elems from a stream equiprobably](#Anchor2) +-[shuffle](#Anchor3) +-[Rand5 to Rand3](#Anchor4) +-[Rand5 to Rand7](#Anchor5) +-[Rand2 to RandN](#Anchor6) + +------- + +-**[Select m elems from n equiprobably]**([Back to Index](#AnchorIndex)) + +已知元素个数n,按顺序等概率的选出m个元素(m < n),不允许重复选取同一元素。注意到“按顺序”,可采用如下算法: +```cpp +void GenRandom(int n, int m){ + for(int i = 0; i <= n-1; i++){ + if(rand()%(n-i) +-**[Select k elems from a stream equiprobably]**([Back to Index](#AnchorIndex)) + +不知道元素个数n,随机等概率选出k个元素,不允许重复选取同一元素。这里为示意便利使用了大小为n的数组,但事实上该算法并不依赖于n。 +```cpp +void pickKElemsFromStream(int A[],int n,int k){ + int pick[k]; + for(int i = 0; i <= k-1; i++){ + pick[i] = i+1; + } + int i = k; + for(; i <= n-1; i++){ + int r = rand(1,i+1); + if(r >= 1 && r <= k){ + pick[r-1] = i+1; + } + } +} +``` +1号结点被选取的概率,遍历到1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +2号结点被选取的概率,遍历到2号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +k+1号结点被选取的概率,遍历到k+1号结点时被选中,且之后不会被覆盖:k/(k+1) * (k+1)/(k+2) * … * (N-1)/N = K/N +最后一个结点被选取的概率,遍历到N号结点时被选中:K/N +从1~N依次计算每个i被最终选取的概率,发现都是K/N。 + +------- + +-**[shuffle]**([Back to Index](#AnchorIndex)) +目标是等概率随机排列数组(洗牌算法)。假设有一个数组,包含n个元素。现在要重新排列这些元素,要求每个元素被放到任何一个位置的概率都相等(即1/n),并且直接在数组上重排(in place),不要生成新的数组。用O(n) 时间、O(1)辅助空间。 + +先想想如果可以开辟另外一块长度为n的辅助空间时该怎么处理,显然只要对n个元素做n次(不放回的)随机抽取就可以了。先从n个元素中任选一个,放入新空间的第一个位置,然后再从剩下的n-1个元素中任选一个,放入第二个位置,依此类推。 + +按照同样的方法,但这次不开辟新的存储空间。第一次被选中的元素就要放入这个数组的第一个位置,但这个位置原来已经有别的(也可能就是这个)元素了,这时候只要把原来的元素跟被选中的元素互换一下就可以了。很容易就避免了辅助空间 + +------- + +-**[Rand5 to Rand3]**([Back to Index](#AnchorIndex)) +利用等概率函数Rand5产生等概率函数Rand3。其中,Rand5是能够等概率产生0,1,2,3,4的随机函数,Rand3是能够等概率产生0,1,2的随机函数。 +```cpp +int Rand3(){ + int x; + do{ + x = Rand5(); + }while(x >= 3); + return x;//0,2,1 +} +``` +只要保证返回的3个数是等概率的即可,每个数的概率都为1/5 + + +-**[Rand5 to Rand7]**([Back to Index](#AnchorIndex)) +利用等概率函数Rand5产生等概率函数Rand7。其中,Rand5是能够等概率产生0,1,2,3,4的随机函数,Rand3是能够等概率产生0,1,2的随机函数。 +```cpp +int Rand7(){ + int x; + do{ + x = Rand()5*5+Rand5(); + }while(x >= 7); + return x; +} +``` +先生成一个比目标大的概率函数,然后在采用之前的方法即可。在生成较大的目标概率函数时,可以使用RandB()*B+RandB()的形式,可保证不重不漏,且每个数产生的概率相同。 + + +-**[Rand2 to RandN]**([Back to Index](#AnchorIndex)) +利用等概率函数Rand2产生等概率函数RandN。其中,Rand5是能够等概率产生0,1的随机函数,RandN是能够等概率产生0...N-1的随机函数。算法中注意对大于小于号的控制,与前两题不同,需要先确定“调用多少次rand2”。 +```cpp +int randN(int n){ + assert(n >= 0); + int factor = 1, factorUpperLimit = 1; + int ret = 0; + while(factorUpperLimit < n){ + factorUpperLimit = factorUpperLimit << 1; + } + do{ + factor = 1; + ret = 0; + while(factor < factorUpperLimit){ + int r = rand2(); // generate 0 or 1 + ret += factor * r; + factor = factor << 1; + } + }while(ret > n-1); + return ret; +} +``` + +更一般化的:于已知的RandX()函数,可以使用模拟X进制生成一个比目标大的概率函数,如 + X^3RandX()+X^2RandX()+XRandX()+RandX() +可以保证不重不漏,因而能等概率的生成数字 + + From 0b23d7f3fb8e0f7af4898d4c32713cdfb841a512 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 11:09:47 +0800 Subject: [PATCH 287/327] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9517e7a..88f2769 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,8 @@ Chapters 6. [Stack](Stack.md) 7. [Geometry](Geometry.md) 8. [STL related](STL related.md) -9. [Others](Others.md) +9. [Probability](Probability.md) +10. [Others](Others.md) ####Engineering 1. Website construction From 7464f9a1e67a3d8fcf3c064e5b8718f5c08f1864 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 11:10:16 +0800 Subject: [PATCH 288/327] Update Probability.md --- Probability.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Probability.md b/Probability.md index ee87e06..231fd05 100644 --- a/Probability.md +++ b/Probability.md @@ -3,7 +3,7 @@ Index: -[Select m elems from n equiprobably](#Anchor1) -[Select k elems from a stream equiprobably](#Anchor2) --[shuffle](#Anchor3) +-[Shuffle](#Anchor3) -[Rand5 to Rand3](#Anchor4) -[Rand5 to Rand7](#Anchor5) -[Rand2 to RandN](#Anchor6) @@ -58,7 +58,7 @@ k+1号结点被选取的概率,遍历到k+1号结点时被选中,且之后 ------- --**[shuffle]**([Back to Index](#AnchorIndex)) +-**[Shuffle]**([Back to Index](#AnchorIndex)) 目标是等概率随机排列数组(洗牌算法)。假设有一个数组,包含n个元素。现在要重新排列这些元素,要求每个元素被放到任何一个位置的概率都相等(即1/n),并且直接在数组上重排(in place),不要生成新的数组。用O(n) 时间、O(1)辅助空间。 先想想如果可以开辟另外一块长度为n的辅助空间时该怎么处理,显然只要对n个元素做n次(不放回的)随机抽取就可以了。先从n个元素中任选一个,放入新空间的第一个位置,然后再从剩下的n-1个元素中任选一个,放入第二个位置,依此类推。 From 854fd27bab7f33908dd4733bc00b65a4caac1dbb Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 11:23:50 +0800 Subject: [PATCH 289/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88f2769..2656ba1 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Chapters 5. [BFS & DFS](BFS & DFS.md) 6. [Stack](Stack.md) 7. [Geometry](Geometry.md) -8. [STL related](STL related.md) +8. [STL Related](STL Related.md) 9. [Probability](Probability.md) 10. [Others](Others.md) From d0739c11c97c001c522ae358eff8e238f8af901f Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 11:24:08 +0800 Subject: [PATCH 290/327] Rename STL related.md to STL Related.md --- STL related.md => STL Related.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename STL related.md => STL Related.md (100%) diff --git a/STL related.md b/STL Related.md similarity index 100% rename from STL related.md rename to STL Related.md From 8baceee66ed41902112df987098e8eb16f978cb6 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 28 Oct 2014 17:08:20 +0800 Subject: [PATCH 291/327] merging --- 7.Area Computation$keyword stack.md | 2 +- Array & String.md | 93 ++++++++++++- BFS & DFS.md | 53 +++++++- Dynamic Programming.md | 44 +++++- Geometry.md | 199 +++++++++++++++++++++++++++- Others.md | 42 +++++- Stack.md | 92 ++++++++++++- Tree & Linkedlist.md | 9 +- 8 files changed, 519 insertions(+), 15 deletions(-) diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md index 7cbe965..742d819 100644 --- a/7.Area Computation$keyword stack.md +++ b/7.Area Computation$keyword stack.md @@ -193,7 +193,7 @@ public: }; ``` -Ex5:[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/) +Ex5:[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/)(Removed) 此题虽然不是计算面积类型题,但因其采用的解题思想与Ex3和Ex4十分相似,即使用一个栈来维护历史状态。更准确的说,“连续的括号”这个状态当且仅当出现无法匹配的')'时才会发生,因此每次匹配成功时分成两种情况来考虑。 * 栈为空:当前匹配成功位置与上次失配位置之间可能有0到多个匹配成功的括号对,因此i-last diff --git a/Array & String.md b/Array & String.md index 6c5a421..f7f1ac3 100644 --- a/Array & String.md +++ b/Array & String.md @@ -5,7 +5,9 @@ Index: -[Find Reverse Pair](#Anchor2) -[Find Min K](#Anchor3) -[Find Number occurs half times](#Anchor4) --[Leetcode:Median of Two Sorted Arrays](#Anchor5) +-[Leetcode:Median of Two Sorted Arrays](#Anchor5) +-[Leetcode:Longest Substring Without Repeating Characters](#Anchor6) +-[Leetcode:Substring with Concatenation of All Words](#Anchor7) ------- @@ -346,3 +348,92 @@ private: return A[pa - 1]; } }; +``` + +------- + +-**[Leetcode:Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/)**([Back to Index](#AnchorIndex)) + +使用快慢指针维护一个区间,使用set时刻保持区间内没有相同字符,核心思想: + + * 如果有重复字符,移动slow指针 + * 如果无重复字符,移动fast指针 + +注意最后一次更新最长区间值。 + +```cpp +class Solution { +public: + int lengthOfLongestSubstring(string s) { + int ret = 0; + int n = s.size(); + if(n == 0) return ret; + int fast = 0, slow = 0; + unordered_set charDict; + while(fast <= n-1){ + if(charDict.find(s[fast]) != charDict.end()){ + int len = fast - slow; + if(len > ret) ret = len; + charDict.erase(charDict.find(s[slow])); + slow++; + }else{ + charDict.insert(s[fast]); + fast++; + } + } + if(fast-slow > ret) ret = fast-slow; + return ret; + } +}; +``` + +------- + +-**[Leetcode:Substring with Concatenation of All Words](http://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/)**([Back to Index](#AnchorIndex)) + +一个比较直观的解法(不一定最优)。维护一个< 单词,个数 >map,假设L中单词长度为wordLen,每次从S中截取L.size()*wordLen的子串,判断该子串是否能完全消耗map中的单词,如果可以,则该起始位置为有效解;如果不能,则将起始位置向后推进wordLen个位置。 + +```cpp +class Solution { +public: + vector findSubstring(string S, vector &L) { + vector ret; + int n = S.size(); + int m = L.size(); + if(n == 0 || m == 0) return ret; + int wordLen = L[0].size(); + map dict; + for(int i = 0 ; i <= m-1; i++){ + if(dict.find(L[i]) != dict.end()){ + dict[L[i]]++; + }else{ + dict[L[i]] = 1; + } + } + for(int i = 0; i <= n-m*wordLen; i++){ + string sub = S.substr(i, m*wordLen); + map dictCopy = dict; + bool isValid = true; + for(int j = 0; j <= m-1; j++){ + string word = sub.substr(j*wordLen, wordLen); + map::iterator itr = dictCopy.find(word); + if(itr != dictCopy.end()){ + if(itr->second == 0){ + isValid = false; + break; + }else{ + dictCopy[word]--; + } + }else{ + isValid = false; + break; + } + } + if(isValid){ + ret.push_back(i); + } + } + return ret; + } +}; +``` \ No newline at end of file diff --git a/BFS & DFS.md b/BFS & DFS.md index 7951def..77f0e3d 100644 --- a/BFS & DFS.md +++ b/BFS & DFS.md @@ -1 +1,52 @@ -NULL +##BFS & DFS + +Index: +-[N-Queens II](#Anchor1) + +------- + +-**[N-Queens II](http://oj.leetcode.com/problems/n-queens-ii/)**([Back to Index](#AnchorIndex)) + +八皇后是递归和回溯的经典问题,递归解法思路比较简明:每次递归选择处在新一行、未被使用列的点,且保证该点与已选择的点斜率绝对值不为1,使用一个Vector来记录已选择的棋子所在列即可,这种做法是有效且正确的。 + +这里介绍求N-queens可行解个数最快的算法[引自Matrix67]。代码如下,思路见注释: +```cpp +class Solution { +public: + int result, upperLim; + int totalNQueens(int n) { + if(n <= 0) return 0; + result = 0; + upperLim = (1 << n) - 1;//掩码,用于过滤掉高于n位的无用bits + recursion(0, 0, 0);//递归初始条件(0x00000000,0x00000000,0x00000000) + return result; + } + + int recursion(int colInfo, int leftDiagonal, int rightDiagonal){ + //3个参数均表示禁位,即之前所选节点对于本次递归所在行选择的限制,来自3方面 + //colInfo表示列禁位,leftDiagonal表示左斜线禁位,rightDiagonal表示右斜线禁位 + //如colInfo == 0x00000003表示最后两列已被选择,不可再次选择 + //leftDiagonal == 0x00000001表示前面选择的点使得本次递归所在行不能选择最后一列 + int pos, p; + //pos表示本次递归所在行可用位置,如0x00000003表示最右两列可用 + //p表示从pos中取出的、只包含“最靠右”的1的数 + if(colInfo == upperLim){ + result++;//所有列已被选择,产生一个可行解 + }else{ + pos = upperLim & ~(colInfo | leftDiagonal | rightDiagonal); + //三个输入参数的或操作是对列、左斜线和右斜线禁位效果合成,取反则是得到可用位 + //与掩码操作过滤掉高于n位的无用bits + while(pos){//不为0表示还有可用位置 + p = pos & -pos;//取出“最靠右”1操作 + pos = pos - p;//消除已选的1 + recursion(colInfo | p, (leftDiagonal | p) << 1, (rightDiagonal | p) >> 1); + //对p的或操作表示该位已选择,对下一层递归起到禁位效果 + //位移的起到表示斜线禁位的效果,举例如下 + //位移前:leftDiagonal == 0001000(7bits), rightDiagonal == 0001000(7bits) + //位移后:leftDiagonal == 0010000(7bits), rightDiagonal == 0000100(7bits) + //显然本次选中第四列会对下一层递归起到第3和第5列禁位效果 + } + } + } +}; +``` diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 0346044..6bd3cda 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -2,10 +2,7 @@ Index: -[Leetcode:Best Time to Buy and Sell Stock III](#Anchor1) --[](#Anchor2) --[](#Anchor3) --[](#Anchor4) --[](#Anchor5) +-[Leetcode:Decode Ways](#Anchor2) ------- @@ -58,4 +55,41 @@ public class Solution { ------- --****([Back to Index](#AnchorIndex)) +-**[Leetcode:Decode Ways](http://oj.leetcode.com/problems/decode-ways/)**([Back to Index](#AnchorIndex)) +分析题意可以发现字符串s的子串s.substr(0,i)对s.substr(0,i-1)和s.substr(0,i-2)存在依赖关系,即可以将原问题分解为小的子问题求解,通过记录子问题求解的结果来快速计算当前问题的结果。当字符串长度为1时,需要dp[0] = 1作为虚拟的初始子问题解。 + +一般的,dp[i]表示s.substr(0,i)的解码方式数量,则dp数组的求解过程如下: + +```cpp +class Solution { +public: + int numDecodings(string s) { + int n = s.size(); + if(n <= 0) return 0; + int dp[n+1]; + memset(dp, 0, sizeof(dp)); + dp[0] = 1; + for(int i = 1; i <= n; i++){ + if(s[i-1] == '0'){ + if(i == 1 || !(s[i-2] == '1' || s[i-2] == '2')){ + dp[i] = 0; + }else{ + dp[i] += dp[i-2]; + } + }else if(s[i-1] >= '1' && s[i-1] <= '6'){ + dp[i] = dp[i-1]; + if(i != 1 && (s[i-2] == '1' || s[i-2] == '2')){ + dp[i] += dp[i-2]; + } + }else{ + dp[i] = dp[i-1]; + if(i != 1 && s[i-2] == '1'){ + dp[i] += dp[i-2]; + } + } + } + return dp[n]; + } +}; +``` + diff --git a/Geometry.md b/Geometry.md index 7951def..ca85b03 100644 --- a/Geometry.md +++ b/Geometry.md @@ -1 +1,198 @@ -NULL +##Geometry + +Index: +-[Leetcode:Max Points on a Line](#Anchor1) +-[Outer Points of Rectangles](#Anchor2) +-[*TODO*::Overlapped Rectangles Area](#Anchor3) + +------- + +-**[Leetcode:Max Points on a Line](http://oj.leetcode.com/problems/max-points-on-a-line/)**([Back to Index](#AnchorIndex)) +对于i、j两个点,看点k是否在i、j确定的直线上。有两种情况: + + * 该直线的斜率无法求出,则判断i、j、k三点横坐标是否相同 + * 三点中任意两点直线斜率相同 + +避免重复计算:遍历点k时,先计算出后面需要用到的几个数。 + +```cpp +class Solution { +public: + + int maxPoints(vector &points) { + if (points.size() == 0) + return 0; + if (points.size() == 1) + return 1; + int result = 0; + for (int i = 0; i < points.size(); i++) { + for (int j = i + 1; j < points.size(); j++) { + bool flag = false; + int cnt = 0; + int a, b, c, d; + if (points[i].x == points[j].x) + flag = true; + else { + a = points[j].x * points[i].y; + b = points[i].x * points[j].y; + c = points[j].x - points[i].x; + d = points[j].y - points[i].y; + } + for (int k = 0; k < points.size(); k++) { + if (flag && points[k].x == points[i].x) + cnt++; + if (!flag && (a + d * points[k].x == b + c * points[k].y)) + cnt++; + } + result = max(result, cnt); + } + } + return result; + } +}; +``` + +------- + +-**[Outer Points of Rectangles]**([Back to Index](#AnchorIndex)) + +给定输入为vector< Rectangle >,其中Rectangle的成员需要包括int x1,int x2和int y,也即在x-y坐标系中,所有Rectangles的底边都在x轴上,因此依靠这3个int值即可唯一确定Rectangle。现要求所有Rectangles组成的图形的外围点集。注意给定的Rectangle已按照x1排序。 +例如,对于输入: +Rectangle 1:(-4,2,2) +Rectangle 2:(-3,1,1) +Rectangle 3:(-3,-1,3) +Rectangle 4:(0,2,2) +Rectangle 5:(2,4,1) +输出点集: +(-4,0),(-3,2),(-3,3),(-1,3),(-1,1),(0,1),(0,2),(2,2),(2,1),(4,1),(4,0) + +对于每个点(矩形的顶点)是否能形成外点取决于该点属于的Retangles区间。例如对于点(a,b)属于2个Retangles区间,也即Retangle 1:(x11,x12,y1)和Rectangle 2:(x21,x22,y2)其中x11<=a<=x12,x21<=a<=x22,如果b>=max(y1,y2),则点(a,b)是外点,且可能额外生成一个交点(a,max(y1,y2)),这个点也是外点。因此问题就转变为对于每个点,如何维持该点所属Retangles区间,考虑使用set。set的底层实现是RBT,对于动态的维护一个集合的最值比较适合,每次操作代价仅为logn。具体做法是: +* 如果该点是某矩形的第一个点(左上角),则计算该点是否是外点,并决定是否生成额外的外点,然后将该矩形加入set,并更新当前最大值 +* 如果该点是某矩形的第二个点(右上角),则在set中查找该矩形,删除它并更新当前最大值,然后计算该点是否是外点,并决定是否生成额外的外点 + +注意对Rectangle的"=="和"<"进行重载。 + +代码如下: +```cpp +#include +#include +#include + +using namespace std; + +class Rectangle{ +public: + int x1; + int x2; + int y; + Rectangle(int _x1, int _x2, int _y){ + x1 = _x1; + x2 = _x2; + y = _y; + } + + bool operator == (const Rectangle & r) const{ + if(x1 == r.x1 && x2 == r.x2 && y == r.y){ + return true; + }else{ + return false; + } + } + + bool operator < (const Rectangle & r) const{ + if(y > r.y){//descending + return true; + }else{ + return false; + } + } +}; + +class Point{ +public: + int x; + int y; + int id;//1 or 2 + Rectangle * rec; + Point(int _x, int _y, int _id,Rectangle* _rec){ + x = _x; + y = _y; + id = _id; + rec = _rec; + } +}; + +bool cmp(const Point* p1, const Point* p2){ + if(p1->x < p2->x || (p1->x == p2->x && p1->y < p2->y)){ + return true; + }else{ + return false; + } +} + +int main(){ + vector inputVec; + inputVec.push_back(new Rectangle(-4,-2,2)); + inputVec.push_back(new Rectangle(-3,1,1)); + inputVec.push_back(new Rectangle(-3,-1,3)); + inputVec.push_back(new Rectangle(0,2,2)); + inputVec.push_back(new Rectangle(2,4,1)); + + vector pointVec; + for(int i = 0; i <= (int)(inputVec.size()-1); i++){ + pointVec.push_back(new Point(inputVec[i]->x1,inputVec[i]->y,1,inputVec[i])); + pointVec.push_back(new Point(inputVec[i]->x2,inputVec[i]->y,2,inputVec[i])); + } + + // sort points + sort(pointVec.begin(),pointVec.end(),cmp); + + set recSet; // RBT + recSet.clear(); + + vector ret;// answer + ret.clear(); + + int currentMaxHeight = 0;//current Highest + + for(int i = 0; i <= (int)(pointVec.size()-1); i++){ + if(pointVec[i]->id == 1){ + if(pointVec[i]->y > currentMaxHeight){ + ret.push_back(new Point(pointVec[i]->x,currentMaxHeight,0,NULL)); + ret.push_back(pointVec[i]); + }else if(pointVec[i]->y == currentMaxHeight){ + ret.push_back(pointVec[i]); + } + recSet.insert(*(pointVec[i]->rec)); + currentMaxHeight = (*(recSet.begin())).y;//update + }else if(pointVec[i]->id == 2){ + set::iterator itr = recSet.find(*(pointVec[i]->rec)); + if(itr != recSet.end()){ + recSet.erase(itr); + } + if(recSet.empty()){ + currentMaxHeight = 0; + }else{ + currentMaxHeight = (*(recSet.begin())).y;//update + } + + if(pointVec[i]->y > currentMaxHeight){ + ret.push_back(pointVec[i]); + ret.push_back(new Point(pointVec[i]->x,currentMaxHeight,0,NULL)); + }else if(pointVec[i]->y == currentMaxHeight){ + ret.push_back(pointVec[i]); + } + } + } + + // output + for(int i = 0; i <= (int)(ret.size()-1); i++){ + cout << "[" << ret[i]->x << "," << ret[i]->y << "]" << endl; + } +} +``` + +------- + +-**[Overlapped Rectangles Area]**([Back to Index](#AnchorIndex)) + diff --git a/Others.md b/Others.md index 70f8fd4..0d7c004 100644 --- a/Others.md +++ b/Others.md @@ -2,10 +2,7 @@ Index: -[Find the number(not exceeding M) only formed by 0 and 1](#Anchor1) --[](#Anchor2) --[](#Anchor3) --[](#Anchor4) --[](#Anchor5) +-[Leetcode:Gray Code](#Anchor2) ------- @@ -71,3 +68,40 @@ public class MyOwn { } } ``` + + +-**[Leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/)**([Back to Index](#AnchorIndex)) +一个普通解法: +```cpp +class Solution { +public: + vector grayCode(int n) { + vector result; + result.push_back(0); + if(n <= 0) return result; + int multiplier = 1; + for(int i = 0;i=0;j--){ + result.push_back(result.at(j)+multiplier); + } + multiplier <<= 1; + } + return result; + } +}; +``` +技巧性较强的解法,二进制转格雷码:gray = (binary) xor (binary >> 1) +```cpp +class Solution { +public: + + vector grayCode(int n) { + vector vec; + int size = 1 << n; + for (int i = 0; i < size; i++) { + vec.push_back(i^(i >> 1)); + } + return vec; + } +}; +``` \ No newline at end of file diff --git a/Stack.md b/Stack.md index 7951def..fe3bed7 100644 --- a/Stack.md +++ b/Stack.md @@ -1 +1,91 @@ -NULL +##Stack + +Index: +-[Leetcode:Evaluate Reverse Polish Notation](#Anchor1) +-[Leetcode:Longest Valid Parentheses](#Anchor2) + +------- + +-**[Leetcode:Evaluate Reverse Polish Notation](http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/)**([Back to Index](#AnchorIndex)) + +逆波兰表达式计算,原理比较简单,用一个栈保存操作数,当遇到操作符时,弹出两个操作数,计算完后将结果压入栈。需要注意的是两个操作数在栈中的先后顺序。 +```java +public class Solution { + public int evalRPN(String[] tokens) { + + int returnValue = 0; + + String operators = "+-*/"; + + Stack stack = new Stack(); + + for(String t : tokens){ + if(!operators.contains(t)){ + stack.push(t); + }else{ + int a = Integer.valueOf(stack.pop()); + int b = Integer.valueOf(stack.pop()); + int index = operators.indexOf(t); + switch(index){ + case 0: + stack.push(String.valueOf(a+b)); + break; + case 1: + stack.push(String.valueOf(b-a)); + break; + case 2: + stack.push(String.valueOf(a*b)); + break; + case 3: + stack.push(String.valueOf(b/a)); + break; + } + } + } + + returnValue = Integer.valueOf(stack.pop()); + + return returnValue; + + } +} +``` + +------- + +-**[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/)**([Back to Index](#AnchorIndex)) + +“连续的括号”这个状态的中断当且仅当出现访问到')'而栈中无'('用于匹配时才会发生。 + +因此每次匹配成功时分成两种情况来考虑。 + * 栈为空:当前匹配成功位置与上次失配位置之间可能有0到多个匹配成功的括号对,因此长度为i-last + * 栈不为空:尚有未被匹配的'(',此时的失配位置就是栈顶的'('的位置,因此长度i-lefts.top() + +```cpp +class Solution { +public: + + int longestValidParentheses(string s) { + int max_len = 0, last = -1; // the position of the last ')' + stack lefts; // keep track of the positions of non-matching '('s + for (int i = 0; i < s.size(); ++i) { + if (s[i] == '(') { + lefts.push(i); + } else { + if (lefts.empty()) { + // no matching left + last = i; + } else { + // find a matching pair + lefts.pop(); + if (lefts.empty()) { + max_len = max(max_len, i - last); + } else { + max_len = max(max_len, i - lefts.top()); + } + } + } + } + return max_len; + } +}; diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index 7951def..7d14cad 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -1 +1,8 @@ -NULL +##Tree & Linkedlist + +Index: +-[*TODO*::Delete one node from BST](#Anchor1) + +------- + +-**[Delete one node from BST]**([Back to Index](#AnchorIndex)) \ No newline at end of file From ddd407cc89cca67c78c43be35cb09656bb4035c8 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 28 Oct 2014 17:12:24 +0800 Subject: [PATCH 292/327] delete 0 and 9 chapters --- 0.Tricky Problems.md | 327 ---------------------------- 9.Sliding window$keywords window.md | 79 ------- 2 files changed, 406 deletions(-) delete mode 100644 0.Tricky Problems.md delete mode 100644 9.Sliding window$keywords window.md diff --git a/0.Tricky Problems.md b/0.Tricky Problems.md deleted file mode 100644 index 8d4094a..0000000 --- a/0.Tricky Problems.md +++ /dev/null @@ -1,327 +0,0 @@ -##Tricky Problems -本章用于收录一些微妙、技巧性较强的问题。一般的,问题所属分类模糊或同类问题较少会导致该问题被收录在Tricky Problems,在条件成熟的情况下可以被移出至新的章节。 - -Ex1:[N-Queens II](http://oj.leetcode.com/problems/n-queens-ii/) - -八皇后是递归和回溯的经典问题,递归解法思路比较简明:每次递归选择处在新一行、未被使用列的点,且保证该点与已选择的点斜率绝对值不为1,使用一个Vector来记录已选择的棋子所在列即可,这种做法是有效且正确的。 -这里介绍求N-queens可行解个数最快的算法。代码如下,思路见注释: -```cpp -class Solution { -public: - int result, upperLim; - int totalNQueens(int n) { - if(n <= 0) return 0; - result = 0; - upperLim = (1 << n) - 1;//掩码,用于过滤掉高于n位的无用bits - recursion(0, 0, 0);//递归初始条件(0x00000000,0x00000000,0x00000000) - return result; - } - - int recursion(int colInfo, int leftDiagonal, int rightDiagonal){ - //3个参数均表示禁位,即之前所选节点对于本次递归所在行选择的限制,来自3方面 - //colInfo表示列禁位,leftDiagonal表示左斜线禁位,rightDiagonal表示右斜线禁位 - //如colInfo == 0x00000003表示最后两列已被选择,不可再次选择 - //leftDiagonal == 0x00000001表示前面选择的点使得本次递归所在行不能选择最后一列 - int pos, p; - //pos表示本次递归所在行可用位置,如0x00000003表示最右两列可用 - //p表示从pos中取出的、只包含“最靠右”的1的数 - if(colInfo == upperLim){ - result++;//所有列已被选择,产生一个可行解 - }else{ - pos = upperLim & ~(colInfo | leftDiagonal | rightDiagonal); - //三个输入参数的或操作是对列、左斜线和右斜线禁位效果合成,取反则是得到可用位 - //与掩码操作过滤掉高于n位的无用bits - while(pos){//不为0表示还有可用位置 - p = pos & -pos;//取出“最靠右”1操作 - pos = pos - p;//消除已选的1 - recursion(colInfo | p, (leftDiagonal | p) << 1, (rightDiagonal | p) >> 1); - //对p的或操作表示该位已选择,对下一层递归起到禁位效果 - //位移的起到表示斜线禁位的效果,举例如下 - //位移前:leftDiagonal == 0001000(7bits), rightDiagonal == 0001000(7bits) - //位移后:leftDiagonal == 0010000(7bits), rightDiagonal == 0000100(7bits) - //显然本次选中第四列会对下一层递归起到第3和第5列禁位效果 - } - } - } -}; -``` -Ex2:[leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/) -一个普通解法: -```cpp -class Solution { -public: - vector grayCode(int n) { - vector result; - result.push_back(0); - if(n <= 0) return result; - int multiplier = 1; - for(int i = 0;i=0;j--){ - result.push_back(result.at(j)+multiplier); - } - multiplier <<= 1; - } - return result; - } -}; -``` -技巧性较强的解法,二进制转格雷码:gray = (binary) xor (binary >> 1) -```cpp -class Solution { -public: - - vector grayCode(int n) { - vector vec; - int size = 1 << n; - for (int i = 0; i < size; i++) { - vec.push_back(i^(i >> 1)); - } - return vec; - } -}; -``` - -Ex3:[Leetcode:Evaluate Reverse Polish Notation](http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/) -一个栈保存操作数,当遇到操作符时,弹出两个操作数,计算完后将结果压入栈 -```java -public class Solution { - public int evalRPN(String[] tokens) { - - int returnValue = 0; - - String operators = "+-*/"; - - Stack stack = new Stack(); - - for(String t : tokens){ - if(!operators.contains(t)){ - stack.push(t); - }else{ - int a = Integer.valueOf(stack.pop()); - int b = Integer.valueOf(stack.pop()); - int index = operators.indexOf(t); - switch(index){ - case 0: - stack.push(String.valueOf(a+b)); - break; - case 1: - stack.push(String.valueOf(b-a)); - break; - case 2: - stack.push(String.valueOf(a*b)); - break; - case 3: - stack.push(String.valueOf(b/a)); - break; - } - } - } - - returnValue = Integer.valueOf(stack.pop()); - - return returnValue; - - } -} -``` -Ex4:[Leetcode:Decode Ways](http://oj.leetcode.com/problems/decode-ways/) -每次遍历时,pre表示上上次解码方法总数,cur表示上次解码总数。假设当前解码方法数为sum,每次遍历初始化sum为0,若当前字符可以被单独解码,sun+=cur,否则sum+=0;若当前字符和上一个字符可以共同解码,sum+=pre,否则sum+=0。计算完之后,pre=cur,cur=sum -```cpp -class Solution { -public: - - int numDecodings(const string &s) { - if (s.empty() || s[0] == '0') return 0; - int prev = 0; - int cur = 1; - // 长度为n 的字符串,有n+1 个阶梯 - for (size_t i = 1; i <= s.size(); ++i) { - if (s[i - 1] == '0') cur = 0; - if (i < 2 || !(s[i - 2] == '1' || - (s[i - 2] == '2' && s[i - 1] <= '6'))) - prev = 0; - int tmp = cur; - cur = prev + cur; - prev = tmp; - } - return cur; - } -}; -``` - -Ex5:[Leetcode:Max Points on a Line](http://oj.leetcode.com/problems/max-points-on-a-line/) -对于i j两个点,看点k是否在ij确定的直线上。有两种情况:1)该直线的斜率无法求出,则判断ijk三点横坐标是否相同;2)三点中任意两点直线斜率相同。避免重复计算:遍历点k时,先计算出后面需要用到的几个数。 -```cpp -class Solution { -public: - - int maxPoints(vector &points) { - if (points.size() == 0) - return 0; - if (points.size() == 1) - return 1; - int result = 0; - for (int i = 0; i < points.size(); i++) { - for (int j = i + 1; j < points.size(); j++) { - bool flag = false; - int cnt = 0; - int a, b, c, d; - if (points[i].x == points[j].x) - flag = true; - else { - a = points[j].x * points[i].y; - b = points[i].x * points[j].y; - c = points[j].x - points[i].x; - d = points[j].y - points[i].y; - } - for (int k = 0; k < points.size(); k++) { - if (flag && points[k].x == points[i].x) - cnt++; - if (!flag && (a + d * points[k].x == b + c * points[k].y)) - cnt++; - } - result = max(result, cnt); - } - } - return result; - } -}; -``` - -Ex6:Outer Points of Rectangles -给定输入为vector< Rectangle >,其中Rectangle的成员需要包括int x1,int x2和int y,也即在x-y坐标系中,所有Rectangles的底边都在x轴上,因此依靠这3个int值即可唯一确定Rectangle。现要求所有Rectangles组成的图形的外围点集。注意给定的Rectangle已按照x1排序。 -例如,对于输入: -Rectangle 1:(-4,2,2) -Rectangle 2:(-3,1,1) -Rectangle 3:(-3,-1,3) -Rectangle 4:(0,2,2) -Rectangle 5:(2,4,1) -输出点集: -(-4,0),(-3,2),(-3,3),(-1,3),(-1,1),(0,1),(0,2),(2,2),(2,1),(4,1),(4,0) - -对于每个点(矩形的顶点)是否能形成外点取决于该点属于的Retangles区间。例如对于点(a,b)属于2个Retangles区间,也即Retangle 1:(x11,x12,y1)和Rectangle 2:(x21,x22,y2)其中x11<=a<=x12,x21<=a<=x22,如果b>=max(y1,y2),则点(a,b)是外点,且可能额外生成一个交点(a,max(y1,y2)),这个点也是外点。因此问题就转变为对于每个点,如何维持该点所属Retangles区间,考虑使用set。set的底层实现是RBT,对于动态的维护一个集合的最值比较适合,每次操作代价仅为logn。具体做法是: -* 如果该点是某矩形的第一个点(左上角),则计算该点是否是外点,并决定是否生成额外的外点,然后将该矩形加入set,并更新当前最大值 -* 如果该点是某矩形的第二个点(右上角),则在set中查找该矩形,删除它并更新当前最大值,然后计算该点是否是外点,并决定是否生成额外的外点 - -注意对Rectangle的"=="和"<"进行重载。 - -代码如下: -```cpp -#include -#include -#include - -using namespace std; - -class Rectangle{ -public: - int x1; - int x2; - int y; - Rectangle(int _x1, int _x2, int _y){ - x1 = _x1; - x2 = _x2; - y = _y; - } - - bool operator == (const Rectangle & r) const{ - if(x1 == r.x1 && x2 == r.x2 && y == r.y){ - return true; - }else{ - return false; - } - } - - bool operator < (const Rectangle & r) const{ - if(y > r.y){//descending - return true; - }else{ - return false; - } - } -}; - -class Point{ -public: - int x; - int y; - int id;//1 or 2 - Rectangle * rec; - Point(int _x, int _y, int _id,Rectangle* _rec){ - x = _x; - y = _y; - id = _id; - rec = _rec; - } -}; - -bool cmp(const Point* p1, const Point* p2){ - if(p1->x < p2->x || (p1->x == p2->x && p1->y < p2->y)){ - return true; - }else{ - return false; - } -} - -int main(){ - vector inputVec; - inputVec.push_back(new Rectangle(-4,-2,2)); - inputVec.push_back(new Rectangle(-3,1,1)); - inputVec.push_back(new Rectangle(-3,-1,3)); - inputVec.push_back(new Rectangle(0,2,2)); - inputVec.push_back(new Rectangle(2,4,1)); - - vector pointVec; - for(int i = 0; i <= (int)(inputVec.size()-1); i++){ - pointVec.push_back(new Point(inputVec[i]->x1,inputVec[i]->y,1,inputVec[i])); - pointVec.push_back(new Point(inputVec[i]->x2,inputVec[i]->y,2,inputVec[i])); - } - - //sort points - sort(pointVec.begin(),pointVec.end(),cmp); - - set recSet; // RBT - recSet.clear(); - - vector ret;// answer - ret.clear(); - - int currentMaxHeight = 0;//current Highest - - for(int i = 0; i <= (int)(pointVec.size()-1); i++){ - if(pointVec[i]->id == 1){ - if(pointVec[i]->y > currentMaxHeight){ - ret.push_back(new Point(pointVec[i]->x,currentMaxHeight,0,NULL)); - ret.push_back(pointVec[i]); - }else if(pointVec[i]->y == currentMaxHeight){ - ret.push_back(pointVec[i]); - } - recSet.insert(*(pointVec[i]->rec)); - currentMaxHeight = (*(recSet.begin())).y;//update - }else if(pointVec[i]->id == 2){ - set::iterator itr = recSet.find(*(pointVec[i]->rec)); - if(itr != recSet.end()){ - recSet.erase(itr); - } - if(recSet.empty()){ - currentMaxHeight = 0; - }else{ - currentMaxHeight = (*(recSet.begin())).y;//update - } - - if(pointVec[i]->y > currentMaxHeight){ - ret.push_back(pointVec[i]); - ret.push_back(new Point(pointVec[i]->x,currentMaxHeight,0,NULL)); - }else if(pointVec[i]->y == currentMaxHeight){ - ret.push_back(pointVec[i]); - } - } - } - - //output - for(int i = 0; i <= (int)(ret.size()-1); i++){ - cout << "[" << ret[i]->x << "," << ret[i]->y << "]" << endl; - } -} -``` - diff --git a/9.Sliding window$keywords window.md b/9.Sliding window$keywords window.md deleted file mode 100644 index 4307c5f..0000000 --- a/9.Sliding window$keywords window.md +++ /dev/null @@ -1,79 +0,0 @@ -##9.Sliding window$keywords window -###*Sliding window - -Ex1:[Leetcode:Longest Substring Without Repeating Characters](http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/) -```cpp -class Solution { -public: - - int lengthOfLongestSubstring(string s) { - const int ASCII_MAX = 26; - int last[ASCII_MAX]; // 记录字符上次出现过的位置 - fill(last, last + ASCII_MAX, -1); // 0 也是有效位置,因此初始化为-1 - int len = 0, max_len = 0; - for (size_t i = 0; i < s.size(); i++, len++) { - if (last[s[i] - 'a'] >= 0) { - max_len = max(len, max_len); - len = 0; - i = last[s[i] - 'a'] + 1; - fill(last, last + ASCII_MAX, -1); // 重新开始 - } - last[s[i] - 'a'] = i; - } - return max(len, max_len); // 别忘了最后一次,例如"abcd" - } -}; -``` -Ex2:[Leetcode:Substring with Concatenation of All Words](http://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/) -```java -public class Solution { - public ArrayList findSubstring(String S, String[] L) { - ArrayList list = new ArrayList(); - int wordLen = L[0].length(); - int numOfWords = L.length; - int length = wordLen * numOfWords; // substring length - if (S.length() < length) - return list; - - // initialize a hash map to facilitate the word match by word counting - HashMap map = new HashMap(); - for (String word : L) { - if (!map.containsKey(word)) { - map.put(word, 1); - } else { - map.put(word, map.get(word) + 1); - } - } - - for (int i = 0; i <= S.length() - length; i++) { - String substr = S.substring(i, i + length); - HashMap map2 = (HashMap) map - .clone(); - // partition the substring into the words of equal length - while (true) { - String word = substr.substring(0, wordLen); - if (map2.containsKey(word)) { - int num = map2.get(word) - 1; - // not found: too many occurrences - if (num < 0) { - break; - } - map2.put(word, num); - substr = substr.substring(wordLen); - // found - if (substr.isEmpty()) { - list.add(i); - break; - } - } - // not found: unmatched - else { - break; - } - } - } - - return list; - } -} -``` From 04df50507667cb3a5a6da08a8dcc2eff7966c2b1 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 28 Oct 2014 21:22:13 +0800 Subject: [PATCH 293/327] merging --- 2.String dp and Array dp$keywords dp.md | 2 +- 6.Tree&keywords tree, transform, visit.md | 12 +- Array & String.md | 11 +- Dynamic Programming.md | 103 ++++++++++ Probability.md | 2 +- Tree & Linkedlist.md | 237 +++++++++++++++++++++- 6 files changed, 352 insertions(+), 15 deletions(-) diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md index 7aede6a..6fc5e6b 100644 --- a/2.String dp and Array dp$keywords dp.md +++ b/2.String dp and Array dp$keywords dp.md @@ -97,7 +97,7 @@ isPalindrome的dp解法: ``` dp的作用其二,记录状态。一般记录int状态或boolean状态,当前状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 -Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/) +Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/)(Removed) 此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 若s3的前i+j-1串已经和s1的前i串与s2的前j-1串匹配,此时若s2的第j个字符和s3的第i+j个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配。s1的i-1加s2的j同理 diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md index 39f2316..9e3870e 100644 --- a/6.Tree&keywords tree, transform, visit.md +++ b/6.Tree&keywords tree, transform, visit.md @@ -1,6 +1,6 @@ ##*6.Tree&keywords tree, transform, visit -Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 +Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。(Removed) 要求不能创建任何新的结点,只调整指针的指向。 该方法采用后序遍历的思想,每次后序遍历时,传入两个指针,分别指向子链表的头尾,之后将两边的子链表和当前节点穿成一个新链表返回。 @@ -68,7 +68,7 @@ int main(){ } ``` -Ex2:[Leetcode:Binary Tree Zigzag Level Order Traversal](http://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) +Ex2:[Leetcode:Binary Tree Zigzag Level Order Traversal](http://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/)(Removed) 首先,既然是层次遍历,肯定需要用到队列。在对每一层进行访问的时候,首先记录队列中的第一个节点和最后一个节点,这是上一层的首尾节点,然后按不同的方向访问每个节点的左右子节点,访问后将该节点弹出队列,这样就能保证加入队列的节点也是有序的。对一层的访问结束后,将方向反转。 @@ -118,7 +118,7 @@ public class Solution { } ``` -Ex3:树中两个结点的最低公共祖先:给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。 +Ex3:树中两个结点的最低公共祖先:给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。(Removed) 这道题有一个简单的方法。使用的是后序遍历方法,返回最低公共祖先。每当遍历到一个节点时,有以下几种情况: * 当前节点等于任一个给定节点。返回当前节点。 @@ -147,7 +147,7 @@ TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { } ``` -Ex4:[Leetcode:Recover Binary Search Tree](http://oj.leetcode.com/problems/recover-binary-search-tree/) +Ex4:[Leetcode:Recover Binary Search Tree](http://oj.leetcode.com/problems/recover-binary-search-tree/)(Removed) 本题采用中序遍历。对于二叉排序树来说,中序遍历序列应该是单调递增的。 * 若被交换的两个元素在原本中序序列中相邻,那么对当前的树中序遍历只会出现一次异常,即后面的数小于前面的数,那将这两个数交换即可 @@ -202,7 +202,7 @@ void recoveryTree(TreeNode * root, TreeNode *& lastNode){ recoveryTree(root->right, lastNode); } ``` -Ex5:[Leetcode:Flatten Binary Tree to Linked List ](http://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/) +Ex5:[Leetcode:Flatten Binary Tree to Linked List ](http://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/)(Removed) 很明显需要采用先序遍历,使用一个指针记录上一个访问的节点,操作步骤为 * 首先将自身与上一个访问的节点相连,如果存在上一个访问节点的话 @@ -250,7 +250,7 @@ public: }; ``` -Ex6:[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal ](http://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) +Ex6:[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal ](http://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/)(Removed) 类似的问题还有利用前序和中序来还原树,都是先确定根的位置并生成根节点,再寻找左右孩子的区间,递归,并将递归返回的左右孩子赋值给根节点即可。 diff --git a/Array & String.md b/Array & String.md index f7f1ac3..4dc0002 100644 --- a/Array & String.md +++ b/Array & String.md @@ -72,7 +72,7 @@ int singleNumber(int A[], int n){ return ret; } -int singleNumberSpecial(int A[], int n){ +int singleNumberSpecial(int A[], int n, int k){ int ret = 0; int count[32]; memset(count,0,sizeof(count)); @@ -83,15 +83,15 @@ int singleNumberSpecial(int A[], int n){ count[i]++; } } - if(count[i]%ARY == 1){ + if(count[i]%ARY == k){ ret |= b; } } return ret; } -vector twoSingleNumber(int A[], int n){ - int twoNum = singleNumberSpecial(A, n); +vector twoSingleNumber(int A[], int n, int k){ + int twoNum = singleNumberSpecial(A, n, k); int b = twoNum & (-twoNum); int B[n],C[n]; int bi = 0,ci = 0; @@ -181,8 +181,7 @@ public class Main { ------- -**Find Min K**([Back to Index](#AnchorIndex)) -问题描述:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 - +问题描述:最小的K个数:输入n个整数,找出其中最小的K个数,并按从小到大顺序打印。 Solution 1: 在这道题中我们利用快速排序的思想,每次都将范围内第一个数作为枢轴,找到前面大于枢轴值的数和后面小于枢轴值的数交换,最后将枢轴值和小于枢轴值的最后一个数交换,完成快速排序。现在数组被分成了两部分,一边小于枢轴值,一边大于枢轴值,等于枢轴值得中间数组下标为t。若k>t,则说明前k个数在后面的子数组里也有,则要对后面排序;若不大于,则不用管后面的子数组。该算法叫做Quick Select,时间复杂度O(n)。 ```cpp diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 6bd3cda..8b41195 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -3,6 +3,8 @@ Index: -[Leetcode:Best Time to Buy and Sell Stock III](#Anchor1) -[Leetcode:Decode Ways](#Anchor2) +-[LeetCode:Interleaving String](#Anchor3) +-[LeetCode:Wildcard Matching](#Anchor3) ------- @@ -93,3 +95,104 @@ public: }; ``` +------- + +-**[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/)**([Back to Index](#AnchorIndex)) + +仔细观察可知,s3的子串需要由s1和s2的子串混合而成,但要求每次从s1和s2中随机按序取出,因此可以使用DP。 + +dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串与 s2中的前j长度串混合组成,对于 i >= 1 和 j >= 1有: + + true, if s1[i-1] == s3[i+j-1] && dp[i-1][j] == true + dp[i][j] = true, if s2[j-1] == s3[i+j-1] && dp[i][j-1] == true + false, otherwise + +若s1的下标为i-1的字符与s3的下标为i+j-1的字符相同,且s1的前i-1子串与s2的前j子串能够拼合成s3的前i+j-1子串,则s1的前i子串可以与s2的前j串拼合成s3的前i+j子串,调换s1和s2的角色亦然。可以简单的理解为此时从s1中选取了下标为i-1的字符作为s3的下标为i+j-1的字符。 + +```java +public class Solution { + public boolean isInterleave(String s1, String s2, String s3) { + if (s3.length() != s1.length() + s2.length()) + return false; + if (s1.length() == 0) + if (!s2.equals(s3)) + return false; + else + return true; + if (s2.length() == 0) + if (!s1.equals(s3)) + return false; + else + return true; + boolean[][] dp = new boolean[s1.length() + 1][s2.length() + 1]; + dp[0][0] = true; + + for (int i = 1; i <= s1.length(); i++) + if (dp[i - 1][0] && s1.charAt(i - 1) == s3.charAt(i - 1)) + dp[i][0] = true; + + for (int j = 1; j <= s2.length(); j++) + if (dp[0][j - 1] && s2.charAt(j - 1) == s3.charAt(j - 1)) + dp[0][j] = true; + + for (int i = 1; i <= s1.length(); i++) + for (int j = 1; j <= s2.length(); j++) { + if (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) + dp[i][j] = true; + if (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1)) + dp[i][j] = true; + } + + return dp[s1.length()][s2.length()]; + } + + public static void main(String[] args) { + Solution m = new Solution(); + String s1 = "aabccabc"; + String s2 = "dbbabc"; + String s3 = "aabdbbccababcc"; + boolean result = m.isInterleave(s1, s2, s3); + System.out.print(result); + } +} +``` + +------- + +-**[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) **([Back to Index](#AnchorIndex)) + +这道题dp[i][j]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] +```cpp +class Solution { +public: + bool isMatchDp(string& t, string& p){ + int tLen = t.length(); + int pLen = p.length(); + + bool dp[pLen+1][tLen+1]; + memset(dp, 0, sizeof(dp)); + + dp[0][0] = true; + + for(int i = 1; i <= pLen; i++){ + if(dp[i-1][0]&&p[i-1]=='*'){ + dp[i][0] = true; + } + } + + for(int i = 1; i <= pLen; i++){ + for(int j = 1; j <= tLen; j++){ + if((p[i-1] == '?')||p[i-1] == t[j-1]){ + dp[i][j] = dp[i-1][j-1]; + }else if(p[i-1] == '*'){ + dp[i][j] = dp[i-1][j]||dp[i][j-1]; + }else{ + dp[i][j] = false; + } + } + } + + return dp[pLen][tLen]; + } +}; +``` \ No newline at end of file diff --git a/Probability.md b/Probability.md index 231fd05..867c547 100644 --- a/Probability.md +++ b/Probability.md @@ -1,4 +1,4 @@ -##Array & String +##Probability Index: -[Select m elems from n equiprobably](#Anchor1) diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index 7d14cad..1445792 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -2,7 +2,242 @@ Index: -[*TODO*::Delete one node from BST](#Anchor1) +-[Transfer BST to sorted double linked list](#Anchor2) +-[LCA](#Anchor3) +-[*TODO*::Judge two tree are the same under swap operation](#Anchor4) +-[Leetcode:Binary Tree Zigzag Level Order Traversal](#Anchor5) +-[Leetcode:Flatten Binary Tree to Linked List](#Anchor6) +-[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal](#Anchor7) +-[Leetcode:Recover Binary Search Tree](#Anchor8) ------- --**[Delete one node from BST]**([Back to Index](#AnchorIndex)) \ No newline at end of file +-**[Delete one node from BST]**([Back to Index](#AnchorIndex)) + + +------- + +-**[Transfer BST to sorted double linked list]**([Back to Index](#AnchorIndex)) +把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表,要求不能创建任何新的结点,只调整指针的指向。 + +该方法采用后序遍历的思想,每次后序遍历时,传入两个指针,分别指向子链表的头尾,之后将两边的子链表和当前节点穿成一个新链表返回。 +```cpp +void transfer(TreeNode* node, TreeNode *& head, TreeNode *& tail){ + if(node==NULL){ + head=NULL; + tail=NULL; + return; + } + TreeNode* l = NULL; + TreeNode* r = NULL; + visit(node->left,head,l); + visit(node->right,r,tail); + if(l!=NULL){ + l->right=node; + node->left=l; + } + else + head=node; + if(r!=NULL){ + r->left=node; + node->right=r; + } + else + tail=node; +} +``` + +------- + +-**[LCA]**([Back to Index](#AnchorIndex)) +树中两个结点的最低公共祖先:给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。 + +使用的是后序遍历方法,返回最低公共祖先。每当遍历到一个节点时,有以下几种情况: + * 当前节点等于任一个给定节点。返回当前节点。 + * 若不是,若遍历完左节点返回null,说明最低公共祖先在右边 + * 若右节点返回null,说明最低公共祖先在左边 + * 若都不为null,说明当前节点为最低公共祖先 + +```cpp +TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { + if (root == NULL) + return NULL; + if (X == root || Y == root) + return root; + TreeNode * left = getLCA(root->m_pLeft, X, Y); + TreeNode * right = getLCA(root->m_pRight, X, Y); + if(left == NULL && right == NULL){ + return NULL; + }else if (left == NULL){ + return right; + }else if (right == NULL){ + return left; + }else{ + return root; + } +} +``` + +------- + +-**[Judge two tree are the same under swap operation]**([Back to Index](#AnchorIndex)) + +------- + +-**[Leetcode:Binary Tree Zigzag Level Order Traversal](http://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/)**([Back to Index](#AnchorIndex)) +无论是zigzag或是正常的层序遍历,利用两个向量都不失为一个通用的好办法,每层遍历后两个向量调换角色即可。 + +```cpp +void zigzagTraversal(TreeNode * root){ + vector q[2]; + int cur = 0, last = 1;//cur is to push, last is to pop + int direction = 1; + q[last].push_back(root); + while(!q[last].empty()){ + while(!q[last].empty()){ + cout << q[last].front()->val << endl; + if(direction){ + if(q[last].front()->left != NULL) q[cur].push_back(q[last].front()->left); + if(q[last].front()->right != NULL) q[cur].push_back(q[last].front()->right); + }else{ + if(q[last].front()->right != NULL) q[cur].push_back(q[last].front()->right); + if(q[last].front()->left != NULL) q[cur].push_back(q[last].front()->left); + } + + q[last].erase(q[last].begin()); + } + + reverse(q[cur].begin(),q[cur].end()); + cur = 1 - cur; + last = 1 - last; + direction = 1 - direction; + } +} +``` + +------- + +-**[Leetcode:Flatten Binary Tree to Linked List](http://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/)**([Back to Index](#AnchorIndex)) + +采用先序遍历,使用一个指针记录上一个访问的节点,递归的对左右子树操作。操作步骤为 + + * 首先将自身与上一个访问的节点相连,如果存在上一个访问节点的话 + * 将上一个访问节点置为自身,为访问左右孩子做准备 + * 保存右子的指针,因为需要将左子置为右子 + * 对左子进行递归 + * 将左子置空 + * 对右子进行递归 + +```cpp +/** + * Definition for binary tree + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode * preVisit; + void flatten(TreeNode *root) { + preVisit = NULL; + recursive(root); + return; + } + + void recursive(TreeNode * root){ + if(root == NULL) return; + if(preVisit != NULL){ + preVisit->right = root;//1.首先将自身与上一个访问的节点相连,如果存在上一个访问节点的话 + } + preVisit = root;//2.将上一个访问节点置为自身,为访问左右孩子做准备 + TreeNode * right = root->right;//3.保存右子的指针,因为需要将左子置为右子 + if(root->left != NULL){ + recursive(root->left);//4.对左子进行递归 + root->left = NULL;//5.将左子置空 + } + if(right != NULL){ + recursive(right);//6.对右子进行递归 + } + return; + } +}; +``` + +------- + +-**[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal](http://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/)**([Back to Index](#AnchorIndex)) + +类似的问题还有利用前序和中序来还原树,都是先确定根的位置并生成根节点,再寻找左右孩子的区间,递归,并将递归返回的左右孩子赋值给根节点即可。 + +```cpp +class Solution { +public: + TreeNode *buildTree(vector &inorder, vector &postorder) { + if(inorder.size() == 0 || postorder.size() == 0) return NULL; + + return build(inorder, postorder, 0, inorder.size()-1, 0, postorder.size()-1); + } + + TreeNode *build(vector &inorder,vector &postorder, int inBegin, int inEnd, int postBegin, int postEnd){ + if(inBegin > inEnd) return NULL; + + TreeNode * root = new TreeNode(postorder[postEnd]); + TreeNode * left = NULL, * right = NULL; + int index = 0; + + for(int i = inBegin; i <= inEnd; i++){ + if(inorder[i] == postorder[postEnd]){ + index = i; + } + } + + int len = index - inBegin; + + left = build(inorder, postorder, inBegin, index-1, postBegin, postBegin+len-1); + right = build(inorder, postorder, index+1, inEnd, postBegin+len, postEnd-1); + + root->left = left; + root->right = right; + + return root; + } +}; +``` + +------- + +-**[Leetcode:Recover Binary Search Tree](http://oj.leetcode.com/problems/recover-binary-search-tree/)**([Back to Index](#AnchorIndex)) + +对于二叉排序树来说,中序遍历序列应该是单调递增的,利用这个性质,检查在本应在递增序列中的值是否出现递减情况。注意相邻两个值交换的情况。 + +```cpp +class Solution { +public: + void recoverTree(TreeNode *root) { + TreeNode * n1 = NULL, * n2 = NULL, *last = NULL; + InOrder(root,last, n1, n2); + if(n1 != NULL && n2 != NULL){ + int temp = n1->val; + n1->val = n2->val; + n2->val = temp; + } + } + + void InOrder(TreeNode *root,TreeNode *& last, TreeNode *& n1, TreeNode *& n2){ + if(root == NULL) return; + InOrder(root->left, last, n1, n2); + if(last != NULL && last->val > root->val){ + if(n1 == NULL){ + n1 = last; + } + n2 = root;//提前记录该值以满足相邻两点交换的情况 + } + last = root; + InOrder(root->right, last, n1, n2); + } +}; +``` + From 6b8daa2352c9c6bc514df8d50bf03cfbdcfc49b7 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 21:36:38 +0800 Subject: [PATCH 294/327] Update and rename STL Related.md to Basic Algorithm & Data Structure.md --- STL Related.md => Basic Algorithm & Data Structure.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) rename STL Related.md => Basic Algorithm & Data Structure.md (96%) diff --git a/STL Related.md b/Basic Algorithm & Data Structure.md similarity index 96% rename from STL Related.md rename to Basic Algorithm & Data Structure.md index 71cba3a..c8aa7ee 100644 --- a/STL Related.md +++ b/Basic Algorithm & Data Structure.md @@ -1,11 +1,8 @@ -##STL related +##Basic Algorithm & Data Structure Index: -[Heap Sort](#Anchor1) -[Union Find Sets](#Anchor2) --[](#Anchor3) --[](#Anchor4) --[](#Anchor5) ------- From 572193a0d25f56b845c1c9fe6359f09909893ea7 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 21:37:17 +0800 Subject: [PATCH 295/327] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2656ba1..9127a30 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Chapters 5. [BFS & DFS](BFS & DFS.md) 6. [Stack](Stack.md) 7. [Geometry](Geometry.md) -8. [STL Related](STL Related.md) +8. [Basic Algorithm & Data Structure](Basic Algorithm & Data Structure.md) 9. [Probability](Probability.md) 10. [Others](Others.md) From 64c14b8c7a58f6aead7df48d384ab843e60576b1 Mon Sep 17 00:00:00 2001 From: jasonZhouChao Date: Tue, 28 Oct 2014 21:39:45 +0800 Subject: [PATCH 296/327] A Careless Error --- Array & String.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Array & String.md b/Array & String.md index f7f1ac3..a0c4f33 100644 --- a/Array & String.md +++ b/Array & String.md @@ -292,7 +292,7 @@ int MoreThanHalf(int a[], int N) int i; for(i=0;i Date: Tue, 28 Oct 2014 22:10:14 +0800 Subject: [PATCH 297/327] merging --- 12.Greedy$keywords greedy.md | 51 -- 6.Tree&keywords tree, transform, visit.md | 446 ------------------ Basic Algorithm & Data Structure.md | 75 +++ ...words Bigdata.md => Big Data Processing.md | 51 +- Greedy Strategy.md | 59 ++- README.md | 1 + 6 files changed, 171 insertions(+), 512 deletions(-) delete mode 100644 12.Greedy$keywords greedy.md delete mode 100644 6.Tree&keywords tree, transform, visit.md rename 10.Big Data Processing$keywords Bigdata.md => Big Data Processing.md (72%) diff --git a/12.Greedy$keywords greedy.md b/12.Greedy$keywords greedy.md deleted file mode 100644 index 2a3b33d..0000000 --- a/12.Greedy$keywords greedy.md +++ /dev/null @@ -1,51 +0,0 @@ -###Greedy$keywords greedy -Ex1:一个n位的数,去掉其中的k位,问怎样去使得留下来的(n-k)位数按原来的前后顺序组成的数最小 -贪心算法,在每次被访问的位置保证有最优解。求一共n位,求其中的m位组成的数最小。那么这个m位的数,最高位应该在原数的最高位到第m位区间找,要不然就不能当第m位了,其余依次递推 -```cpp -#include -#include -#include -using namespace std; - -int findMinIndex(int arr[], int beg, int end) -{ - if(beg > end) - return -1; - int minv = arr[beg]; - int minIndex = beg; - for(int i = beg + 1; i <= end; ++i) - { - if(arr[i] < minv) - { - minv = arr[i]; - minIndex = i; - } - } - return minIndex; -} - -int getRemain(int arr[], int size, int k) -{ - int rev = 0, revIndex = -1; - for(int i = size - k; i < size; ++i) - { - revIndex = findMinIndex(arr, revIndex + 1, i); - rev = rev * 10 + arr[revIndex]; - } - return rev; -} - -int main() -{ - int arr[] = {3, 1, 6, 4, 8, 5, 7}; - size_t size = sizeof(arr) / sizeof(int); - - int remainNum; - for (int k = size-1; k > 0; --k) - { - remainNum = getRemain(arr, size, size - k); - cout << "When k = " << k << ", the remaining value is:" << remainNum << endl; - } - -} -``` diff --git a/6.Tree&keywords tree, transform, visit.md b/6.Tree&keywords tree, transform, visit.md deleted file mode 100644 index 9e3870e..0000000 --- a/6.Tree&keywords tree, transform, visit.md +++ /dev/null @@ -1,446 +0,0 @@ -##*6.Tree&keywords tree, transform, visit - -Ex1:把二元查找树转变成排序的双向链表。输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。(Removed) -要求不能创建任何新的结点,只调整指针的指向。 - -该方法采用后序遍历的思想,每次后序遍历时,传入两个指针,分别指向子链表的头尾,之后将两边的子链表和当前节点穿成一个新链表返回。 -```cpp -#include -#include -using namespace std; -struct TreeNode{ - int val; - TreeNode* left; - TreeNode* right; - TreeNode(int x) : val(x),left(NULL),right(NULL){} -}; - -TreeNode* buildTree(){ - TreeNode* node1 = new TreeNode(1); - TreeNode* node2 = new TreeNode(2); - TreeNode* node3 = new TreeNode(3); - TreeNode* node4 = new TreeNode(4); - TreeNode* node5 = new TreeNode(5); - TreeNode* node6 = new TreeNode(6); - node4->left = node2; - node4->right = node5; - node2->left = node1; - node2->right = node3; - node5->right = node6; - - return node4; -} - -void visit(TreeNode* node, TreeNode *& head, TreeNode *& tail){ - if(node==NULL){ - head=NULL; - tail=NULL; - return; - } - TreeNode* l = NULL; - TreeNode* r = NULL; - visit(node->left,head,l); - visit(node->right,r,tail); - if(l!=NULL){ - l->right=node; - node->left=l; - } - else - head=node; - if(r!=NULL){ - r->left=node; - node->right=r; - } - else - tail=node; -} - -int main(){ - TreeNode* head = NULL; - TreeNode* tail = NULL; - TreeNode* root = buildTree(); - visit(root,head,tail); - for(TreeNode* node=head;node!=NULL;node=node->right) - printf("%d ",node->val); - - system("pause"); - return 0; -} -``` - -Ex2:[Leetcode:Binary Tree Zigzag Level Order Traversal](http://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/)(Removed) - -首先,既然是层次遍历,肯定需要用到队列。在对每一层进行访问的时候,首先记录队列中的第一个节点和最后一个节点,这是上一层的首尾节点,然后按不同的方向访问每个节点的左右子节点,访问后将该节点弹出队列,这样就能保证加入队列的节点也是有序的。对一层的访问结束后,将方向反转。 - -Added by [@sc703bupt](https://github.com/sc703bupt):对于层序遍历来说需要分层处理的情况,一种是使用两个指针指向队列中的同一层的头和尾,另一种办法是使用两个队列,两个队列角色在一方为空后调换。 -```java -import java.util.ArrayList; -import java.util.LinkedList; - -public class Solution { - public ArrayList> zigzagLevelOrder(TreeNode root) { - ArrayList> result = new ArrayList>(); - if (root == null) - return result; - LinkedList queue = new LinkedList(); - queue.add(root); - boolean flag = true; - while (!queue.isEmpty()) { - ArrayList tmp = new ArrayList(); - if (flag) { - TreeNode end = queue.getLast(); - TreeNode node = null; - while (node != end) { - node = queue.pollFirst(); - tmp.add(node.val); - if (node.left != null) - queue.add(node.left); - if (node.right != null) - queue.add(node.right); - } - } else { - TreeNode start = queue.getFirst(); - TreeNode node = null; - while (node != start) { - node = queue.pollLast(); - tmp.add(node.val); - if (node.right != null) - queue.addFirst(node.right); - if (node.left != null) - queue.addFirst(node.left); - } - } - flag = !flag; - result.add(tmp); - } - return result; - } -} -``` - -Ex3:树中两个结点的最低公共祖先:给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。(Removed) - -这道题有一个简单的方法。使用的是后序遍历方法,返回最低公共祖先。每当遍历到一个节点时,有以下几种情况: -* 当前节点等于任一个给定节点。返回当前节点。 -* 若不是,若遍历完左节点返回null,说明最低公共祖先在右边 -* 若右节点返回null,说明最低公共祖先在左边 -* 若都不为null,说明当前节点为最低公共祖先 - -Added by [@sc703bupt](https://github.com/sc703bupt):递归方法即是返回当前树是否存在两个节点的其中一个,当某个节点得到其两个子树都有目标节点时,其自身即为LCA。 -```cpp -TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { - if (root == NULL) - return NULL; - if (X == root || Y == root) - return root; - TreeNode * left = getLCA(root->m_pLeft, X, Y); - TreeNode * right = getLCA(root->m_pRight, X, Y); - if(left == NULL && right == NULL){ - return NULL; - }else if (left == NULL){ - return right; - }else if (right == NULL){ - return left; - }else{ - return root; - } -} -``` - -Ex4:[Leetcode:Recover Binary Search Tree](http://oj.leetcode.com/problems/recover-binary-search-tree/)(Removed) - -本题采用中序遍历。对于二叉排序树来说,中序遍历序列应该是单调递增的。 -* 若被交换的两个元素在原本中序序列中相邻,那么对当前的树中序遍历只会出现一次异常,即后面的数小于前面的数,那将这两个数交换即可 -* 若不相邻,则会出现两次异常。这种情况下我们要记录第一次异常中的首和第二次异常中的尾,将两个数交换。 - -```java -public class Solution { - TreeNode pre; - TreeNode n1; - TreeNode n2; - - public void recoverTree(TreeNode root) { - visit(root); - if (n1 != null) { - int tmp = n1.val; - n1.val = n2.val; - n2.val = tmp; - } - } - - public void visit(TreeNode root) { - if (root == null) - return; - visit(root.left); - if (pre == null) - pre = root; - else if (root.val < pre.val) { - n2 = root; - if (n1 == null) - n1 = pre; - } - pre = root; - visit(root.right); - } -} -``` -C++版本代码 -```cpp -void recoveryTree(TreeNode * root, TreeNode *& lastNode){ - if(root == NULL) return; - - recoveryTree(root->left, lastNode); - - if(lastNode != NULL && root->val < lastNode->val){ - if(e1 == NULL){ - e1 = lastNode; - }else{ - e2 = root; - } - } - lastNode = root; - recoveryTree(root->right, lastNode); -} -``` -Ex5:[Leetcode:Flatten Binary Tree to Linked List ](http://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/)(Removed) - -很明显需要采用先序遍历,使用一个指针记录上一个访问的节点,操作步骤为 -* 首先将自身与上一个访问的节点相连,如果存在上一个访问节点的话 -* 将上一个访问节点置为自身,为访问左右孩子做准备 -* 保存右子的指针,因为需要将左子置为右子 -* 对左子进行递归 -* 将左子置空 -* 对右子进行递归 - -```cpp -/** - * Definition for binary tree - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode(int x) : val(x), left(NULL), right(NULL) {} - * }; - */ -class Solution { -public: - TreeNode * preVisit; - void flatten(TreeNode *root) { - preVisit = NULL; - recursive(root); - return; - } - - void recursive(TreeNode * root){ - if(root == NULL) return; - if(preVisit != NULL){ - preVisit->right = root;//1.首先将自身与上一个访问的节点相连,如果存在上一个访问节点的话 - } - preVisit = root;//2.将上一个访问节点置为自身,为访问左右孩子做准备 - TreeNode * right = root->right;//3.保存右子的指针,因为需要将左子置为右子 - if(root->left != NULL){ - recursive(root->left);//4.对左子进行递归 - root->left = NULL;//5.将左子置空 - } - if(right != NULL){ - recursive(right);//6.对右子进行递归 - } - return; - } -}; -``` - -Ex6:[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal ](http://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/)(Removed) - -类似的问题还有利用前序和中序来还原树,都是先确定根的位置并生成根节点,再寻找左右孩子的区间,递归,并将递归返回的左右孩子赋值给根节点即可。 - -```cpp -class Solution { -public: - TreeNode *buildTree(vector &inorder, vector &postorder) { - if(inorder.size() == 0 || postorder.size() == 0) return NULL; - - return build(inorder, postorder, 0, inorder.size()-1, 0, postorder.size()-1); - } - - TreeNode *build(vector &inorder,vector &postorder, int inBegin, int inEnd, int postBegin, int postEnd){ - if(inBegin > inEnd) return NULL; - - TreeNode * root = new TreeNode(postorder[postEnd]); - TreeNode * left = NULL, * right = NULL; - int index = 0; - - for(int i = inBegin; i <= inEnd; i++){ - if(inorder[i] == postorder[postEnd]){ - index = i; - } - } - - int len = index - inBegin; - - left = build(inorder, postorder, inBegin, index-1, postBegin, postBegin+len-1); - right = build(inorder, postorder, index+1, inEnd, postBegin+len, postEnd-1); - - root->left = left; - root->right = right; - - return root; - } -}; -``` - -Ex7:Tree Traversal 递归和非递归版本 -树的三种遍历方法的递归和非递归版本 - -```cpp -#include -#include -#include - -using namespace std; - -class TreeNode{ -public: - int val; - TreeNode * left; - TreeNode * right; - TreeNode(int val){ - this->val = val; - left = NULL; - right = NULL; - } -}; - -void preOrderTraversal(TreeNode * root); -void preOrderTraversalNonRecursive(TreeNode * root); -void inOrderTraversal(TreeNode * root); -void inOrderTraversalNonRecursive(TreeNode * root); -void postOrderTraversal(TreeNode * root); -void postOrderTraversalNonRecursive(TreeNode * root); - -int main(){ - TreeNode * n4 = new TreeNode(4); - TreeNode * n2 = new TreeNode(2); - TreeNode * n6 = new TreeNode(6); - - n4->left = n2; - n4->right = n6; - - TreeNode * n1 = new TreeNode(1); - TreeNode * n3 = new TreeNode(3); - - n2->left = n1; - n2->right = n3; - - TreeNode * n5 = new TreeNode(5); - TreeNode * n7 = new TreeNode(7); - - n6->left = n5; - n6->right = n7; - - cout<< "preOrderTraversal:"; - preOrderTraversal(n4); - cout<val << " "; - if(root->left != NULL) preOrderTraversal(root->left); - if(root->right != NULL) preOrderTraversal(root->right); -} - -void preOrderTraversalNonRecursive(TreeNode * root){ - stack stk; - for(;;){ - while(root != NULL){ - cout << root->val << " ";//visit - stk.push(root); - root = root->left; - } - if(!stk.empty()){ - root = stk.top(); - root = root->right; - stk.pop(); - }else{ - return; - } - } -} - -void inOrderTraversal(TreeNode * root){ - if(root == NULL){ - return; - } - if(root->left != NULL) inOrderTraversal(root->left); - cout << root->val << " "; - if(root->right != NULL) inOrderTraversal(root->right); -} - -void inOrderTraversalNonRecursive(TreeNode * root){ - stack stk; - for(;;){ - while(root != NULL){ - stk.push(root); - root = root->left; - } - if(!stk.empty()){ - root = stk.top(); - stk.pop(); - cout << root->val << " ";//visit - root = root->right; - }else{ - return; - } - } -} - -void postOrderTraversal(TreeNode * root){ - if(root == NULL){ - return; - } - if(root->left != NULL) postOrderTraversal(root->left); - if(root->right != NULL) postOrderTraversal(root->right); - cout << root->val << " "; -} - -void postOrderTraversalNonRecursive(TreeNode * root){ - stack stk; - TreeNode * lastVisit = NULL; - for(;;){ - while(root != NULL){ - stk.push(root); - root = root->left; - } - while(!stk.empty()){ - root = stk.top(); - if(root->right == lastVisit || root->right == NULL){ - cout << root->val << " ";//visit - lastVisit = root; - stk.pop(); - }else{ - root = root->right;//root can't be NULL here - break; - } - } - if(stk.empty()) return; - } -} -``` diff --git a/Basic Algorithm & Data Structure.md b/Basic Algorithm & Data Structure.md index c8aa7ee..7a37996 100644 --- a/Basic Algorithm & Data Structure.md +++ b/Basic Algorithm & Data Structure.md @@ -3,6 +3,7 @@ Index: -[Heap Sort](#Anchor1) -[Union Find Sets](#Anchor2) +-[Nonrecursive Tree Traversal](#Anchor3) ------- @@ -70,3 +71,77 @@ void swap(int * a, int * b){ ------- -**Union Find Sets**([Back to Index](#AnchorIndex)) + +------- + +-**Nonrecursive Tree Traversal**([Back to Index](#AnchorIndex)) + +掌握三种树的遍历的非递归版本是非常必要的,代码如下。 + +先序遍历: +```cpp +void preOrderTraversalNonRecursive(TreeNode * root){ + stack stk; + for(;;){ + while(root != NULL){ + cout << root->val << " ";//visit + stk.push(root); + root = root->left; + } + if(!stk.empty()){ + root = stk.top(); + root = root->right; + stk.pop(); + }else{ + return; + } + } +} +``` + +中序遍历: +```cpp +void inOrderTraversalNonRecursive(TreeNode * root){ + stack stk; + for(;;){ + while(root != NULL){ + stk.push(root); + root = root->left; + } + if(!stk.empty()){ + root = stk.top(); + stk.pop(); + cout << root->val << " ";//visit + root = root->right; + }else{ + return; + } + } +} +``` + +后序遍历: +```cpp +void postOrderTraversalNonRecursive(TreeNode * root){ + stack stk; + TreeNode * lastVisit = NULL; + for(;;){ + while(root != NULL){ + stk.push(root); + root = root->left; + } + while(!stk.empty()){ + root = stk.top(); + if(root->right == lastVisit || root->right == NULL){ + cout << root->val << " ";//visit + lastVisit = root; + stk.pop(); + }else{ + root = root->right;//root can't be NULL here + break; + } + } + if(stk.empty()) return; + } +} +``` \ No newline at end of file diff --git a/10.Big Data Processing$keywords Bigdata.md b/Big Data Processing.md similarity index 72% rename from 10.Big Data Processing$keywords Bigdata.md rename to Big Data Processing.md index 7d13d18..c466539 100644 --- a/10.Big Data Processing$keywords Bigdata.md +++ b/Big Data Processing.md @@ -1,28 +1,51 @@ ##Big Data Processing -###*Big Data Processing + 大数据处理往往因数据量过大导致数据无法全部加载入内存,又或即便能够加载入内存,处理速度无法保证。此外,大数据问题又被许多因素制约,比如网络传输带宽,内存空间限制,响应时间,因此产生了不少有趣的问题,而这些问题的解决离不开分治思想,内存排序-外存合并以及哈希映射的设计与实现。 -**Ex1:给定1台主机和100台从机,从机只能与主机通信,且通信速率仅有1KB/s。每台从机上有2G个INT型数据,要求在合理的时间范围内求出所有数据的中位数。** + +Index: +-[Find median among numbers spread in distributed system](#Anchor1) +-[Find frequencies of each IPs](#Anchor2) +-[Bit-map](#Anchor3) + +------- + +-**Find median among numbers spread in distributed system**([Back to Index](#AnchorIndex)) + +给定1台主机和100台从机,从机只能与主机通信,且通信速率仅有1KB/s。每台从机上有2G个INT型数据,要求在合理的时间范围内求出所有数据的中位数。 此题的思考思路如下。通信速率1KB/s说明通信速率非常低,基本不可能用于传输大量的数据,1s也只能传输256个INT数字,2G的传输不可能在合理时间内完成,通信带宽只能用于传输统计信息,如最大最小值,自身的中位数,平均值等信息。题目要求求出所有数据的中位数。 + 考虑中位数的性质,对于一个长度为N的数组,其中位数左侧和右侧各有(N-1/2)个数字,从左侧和右侧分别剔除x个数不会影响原中位数的性质。 + 对于题目给出的无序数据,先进行内存排序(如快排),再进行区块划分。假设到INT数据的范围为D,划分的区块长度为L(如0-200,200-400...),则区块数量为D/L。此时统计每个区块的包含数字的个数得到(N1,N2..N(D/L)),向主机发送这个信息并接收其他所有从机的同类信息,可获得如下信息矩阵 -从机1:(N1,N2..N(D/L)) -从机2:(N1,N2..N(D/L)) -. -. -. -从机100:(N1,N2..N(D/L)) -对应列相加后得到(TN1,TN2..TN(D/L)),此时容易知道要求中位数为第Mid = (2G/4)/2 = 256M个,从TN数组的左侧开始做减法,即Mid -= TNk直到Mid小于0,即可知道中位数所在区间。 -如果该区间还是过大,则可递归进行上述过程,再次分块并求Mid' = Mid - ΣTNk,直到求出最后结果。 + 从机1:(N1,N2..N(D/L)) + 从机2:(N1,N2..N(D/L)) + . + . + . + 从机100:(N1,N2..N(D/L)) + +对应列相加后得到 + + (TN1,TN2..TN(D/L)) + +此时容易知道要求中位数为第Mid = (2G/4)/2 = 256M个,从TN数组的左侧开始做减法,即Mid -= TNk直到Mid小于0,即可知道中位数所在区间。 + +如果该区间还是过大,则可递归进行上述过程,再次分块并求Mid' = Mid - ΣTNk,直到求出最后结果。 -**Ex2:给定100G条IP数据以及一张划分IP域的表,使用最快的方法统计出每个IP域的IP个数。** +------- + +-**Find frequencies of each IPs**([Back to Index](#AnchorIndex)) +给定100G条IP数据以及一张划分IP域的表,使用最快的方法统计出每个IP域的IP个数。 -IP由32位组成,共4G个,因此100G条IP必然存在重复,考虑使用一个MAP进行压缩,压缩比达到25:1。又因为划分IP域的表的是单调递增的,如果使用一个有序的MAP,则可以在遍历MAP的同时统计出所有结果。 +IP由32位组成,共4G个,因此100G条IP必然存在重复,考虑使用一个MAP进行压缩,压缩比达到25:1。又因为划分IP域的表的是单调递增的,如果使用一个有序的MAP,则可以在遍历MAP的同时统计出所有结果。 +------- + +-**Bit-map**([Back to Index](#AnchorIndex)) -**Ex3:Bit-map** 所谓的Bit-map就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省空间 ```cpp //定义每个Byte中有8个Bit位 @@ -77,4 +100,4 @@ int main() { return 0; } -``` +``` \ No newline at end of file diff --git a/Greedy Strategy.md b/Greedy Strategy.md index 7951def..0c062a8 100644 --- a/Greedy Strategy.md +++ b/Greedy Strategy.md @@ -1 +1,58 @@ -NULL +##Greedy Strategy + +Index: +-[Cutting digits to make min number](#Anchor1) + +------- + +-**Cutting digits to make min number**([Back to Index](#AnchorIndex)) + +一个n位的数,去掉其中的k位,问怎样去使得留下来的(n-k)位数按原来的前后顺序组成的数最小贪心算法,在每次被访问的位置保证有最优解。求一共n位,求其中的m位组成的数最小。那么这个m位的数,最高位应该在原数的最高位到第m位区间找,要不然就不能当第m位了,其余依次递推。 +```cpp +#include +#include +#include +using namespace std; + +int findMinIndex(int arr[], int beg, int end) +{ + if(beg > end) + return -1; + int minv = arr[beg]; + int minIndex = beg; + for(int i = beg + 1; i <= end; ++i) + { + if(arr[i] < minv) + { + minv = arr[i]; + minIndex = i; + } + } + return minIndex; +} + +int getRemain(int arr[], int size, int k) +{ + int rev = 0, revIndex = -1; + for(int i = size - k; i < size; ++i) + { + revIndex = findMinIndex(arr, revIndex + 1, i); + rev = rev * 10 + arr[revIndex]; + } + return rev; +} + +int main() +{ + int arr[] = {3, 1, 6, 4, 8, 5, 7}; + size_t size = sizeof(arr) / sizeof(int); + + int remainNum; + for (int k = size-1; k > 0; --k) + { + remainNum = getRemain(arr, size, size - k); + cout << "When k = " << k << ", the remaining value is:" << remainNum << endl; + } + +} +``` \ No newline at end of file diff --git a/README.md b/README.md index 9127a30..5cfeabb 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Chapters ####Basic Knowledge 1. [Basic Java Concepts](Basic Java Concepts.md) 2. [NIO](NIO.md) +3. [Big Data Processing](Big Data Processing.md) Core contributors ------------ From 6da77f68bec1a88b0e5c979e6430525587c549a6 Mon Sep 17 00:00:00 2001 From: Chen Shen Date: Tue, 28 Oct 2014 22:10:53 +0800 Subject: [PATCH 298/327] =?UTF-8?q?Delete=2015.=E5=A4=A7=E5=9E=8B=E7=BD=91?= =?UTF-8?q?=E7=AB=99=E5=BC=80=E5=8F=91.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 "15.\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" diff --git "a/15.\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" "b/15.\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" deleted file mode 100644 index afad75c..0000000 --- "a/15.\345\244\247\345\236\213\347\275\221\347\253\231\345\274\200\345\217\221.md" +++ /dev/null @@ -1,2 +0,0 @@ -##1.多线程 -###[锁](http://blog.csdn.net/natian306/article/details/18504111) From 912ecd2ef0f8dffc7d8ad77ac7ebcc3f3aa868d3 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 28 Oct 2014 22:22:53 +0800 Subject: [PATCH 299/327] merging --- 11.String$keywords string.md | 2 +- 13.Java$keywords java.md | 275 -------------------------- Basic Algorithm & Data Structure.md | 59 ++++++ Basic Java Concepts.md | 290 +++++++++++++++++++++++++++- 4 files changed, 349 insertions(+), 277 deletions(-) delete mode 100644 13.Java$keywords java.md diff --git a/11.String$keywords string.md b/11.String$keywords string.md index fcc44c1..a65cdd5 100644 --- a/11.String$keywords string.md +++ b/11.String$keywords string.md @@ -179,7 +179,7 @@ public: }; ``` -Ex5:KMP算法 +Ex5:KMP算法(Removed) 即字符串匹配问题。首先要算出字符串的覆盖数组,当发生在j长度失配时,只要把pattern向右移动j-overlay(j)长度就可以了。 ```cpp diff --git a/13.Java$keywords java.md b/13.Java$keywords java.md deleted file mode 100644 index 37b8b58..0000000 --- a/13.Java$keywords java.md +++ /dev/null @@ -1,275 +0,0 @@ -##Java -严格的说本章不应收录在本github项目中,但考虑到语言本身对于算法的实现也是有影响,现将一些较为重要和较难记忆理解的Java知识收录此处共查阅学习。 -###*与C++的一些不同之处 -1.char类型的宽度为16bit;c++为8bit -2.没有unsigned修饰符;c++有 -3.下列代码是非法的;c++合法 -```cpp - int x = 12; - { - int x = 13; - } -``` -4.String s;并没有创建一个对象,只是声明了一个引用;c++在栈上创建了一个对象 -5.类成员会获得默认值;c++不会自动初始化类成员 -6.类成员可以直接初始化;c++的类成员不能直接初始化,可以在构造函数里初始化 -7.对于对象参数,默认为传引用;c++默认为传值 -8.=号赋值只是使新的引用指向了旧的对象,也即新旧引用指向同一个对象;c++则会生成一个新的对象 -9.>>>号是高位补0右移运算符;c++无此符号 -10.拥有finalize()方法;c++只有析构函数 -11.可以使用int[] A或int A[]方式声明一个数组,因为是引用,不可以指定数组大小;c++只能使用int A[]的方式,可以指定数组大小 -12.默认开启动态绑定;C++使用virtual关键字才能开启动态绑定 -13.所有容器都有共同的基类Collection;C++容器之间没有共同的基类,依赖迭代器达成共性 -14.泛型和模板对比: - >*C++模板在编译期检查对模板对象的调用是否在该对象所属类总存在来保证类型安全 - >*Java由于采用了类型擦除,仅使用T会使对象所属类被擦除到Object,而非其真正所属类,因此也就无法验证调用是否合法,因此要使用T extends Type来表示泛型边界(一个好的例子见Thinking in Java P375) -15.Comparable接口的方法compareTo(Type obj)返回的值包括-1,0,1,分别表示当前对象小于,等于,大于参数obj; - C++的比较函数cmp(Type obj1, Type obj2)则只返回true和false,obj1<=obj2返回true,反之返回false - -###*Java重要知识点 -1.java.lang是默认导入每个java文件的 -2.equals()默认行为是比较引用,可以重写;==判断的是引用的内存地址是否相同 -3.对byte和short的位移操作要特别小心,它们会被转换为int型然后位移,这会导致不正确的结果 -4.bool类型不允许任何类型转换,也不允许使用类似while(1)的语句,0,1并不等同于false和true,必须使用while(true) -5.float或double转为整形值时,总是对该数字进行截尾 -6.提升:对基本数据类型进行算术运算或按位运算时,低于int型的数据类型(char、byte和short)总是会先转换为int再运算;数据类型大的类型决定了结果的类型 -7.不能仅仅使用返回值不同的方法作为重载方法,应该使参数列表不同(至少是顺序不同) -8.如果已经定义了一个构造器,无论是否有参数,编译器不会自动创建默认构造器 -9.this的三个应用场合: - *用于引用自身对象的成员,特别是因为成员与方法参数重名 - *用于在一个重载的构造器中调用另一个构造器,此时必须放在第一句,且只有构造器可以调用其他构造器 - *用于返回自身对象的引用 -10.被static修饰的方法内不能调用非static方法和成员,因为非static方法和成员依赖具体的对象(除非这个静态方法获得自身类的一个对象实例并通过该实例调用非晶态方法) -11.Java没有C++的析构函数,取而代之是finalize(),用于释放非Java代码(如native C)申请的系统资源,由GC调用(不要直接调用finalize()方法),而GC的调用时机是不能被预期的。 -12.Java的GC机制包括两种:"停止-复制"和“标记-清扫”,都是从堆栈和静态存储区开始扫描引用。采用自适应技术在两种技术中切换,碎片多时用“停止-复制”,碎片少时用“标记-清扫”。 -13.不同于类成员,局部变量必须被初始化,否则报错。 -14.类成员的初始化顺序:类加载->new操作(或访问静态域,此行为不会导致空间分配)->静态成员初始化(包括静态块)(只发生一次,如果以前new操作/访问静态域操作出现过则不再初始化)->分配空间,非静态成员初始化(包括非静态块)->构造方法。类成员变量的初始化(包括但不限于默认初始化行为)绝对先于构造器的对类成员的初始化操作。 - 一个继承自A类的B类对象的初始化顺序:类B加载->类A加载->类A的静态成员初始化->类B的静态成员初始化->类A非静态成员初始化->类A的构造方法->类B非静态成员初始化->类B的构造方法 -15.构造器是static方法。 -16.一下两种声明和初始化数组的方式都是合法的,最后一个逗号是可选的 - *Integer[] a = {new Integer(1), new Integer(2), 3, }//Auto Boxing - *Integer[] b = new Integer[]{new Integer(1), new Integer(2), 3, }//Auto Boxing -17.可变参数形如void function(type... args),三个注意点: - *可以给可变参数列表传0个参数 - *可变参数列表不依赖于Auto Boxing - *尽量避免在多个重载方法中使用可变参数,可能会引起歧义 - void function(int a, int... args){} - void function(int... args){} - *如果必须使用,添加非可变参数如 - void function(int a, int... args){} - void function(string b, int... args){} -18.enum的使用跟类相近,可以使用在switch内。可以对一个enum对象赋予枚举类型值,如EnumType et = EnumType.type1 -19.一个Java源文件中最多只能有一个public类,当有一个public类时,源文件名必须与之一致,否则无法编译,如果源文件中没有一个public类,则文件名与类中没有一致性要求。至于main()不是必须要放在public类中才能运行程序。总结出如下4点 - *Java源文件可以有public类,也可以没有 - *如果有public类,则该public类必须与文件名同名 - *如果没有public类,则不要求有与文件名同名的类 - *main()方法的放在哪个类里没有硬性要求,跟是否在public类中也没有关系,一个文件中多个类可以各自持有一个main()方法,都可以用java命令运行 -20.Java解释器的运行过程是首先找出环境变量CLASSPATH用于查找.class的根目录,然后加载。 -21.访问权限控制的等级:public->protected->包访问权限->private -22.类的权限控制的等级:public->包访问权限,不可以是protected或private的 -23.一个类的构造器是private的,任何其他类无法直接创建该类,只有该类的static方法或对static对象赋值(即非延迟化实现)才可以创建一个该类的对象 -24.使用成员的访问控制主要有两个原因: - *使用户不要碰触他们不该碰触的部分 - *更重要的是,可以让类的设计者改变类的内部实现而不影响会对客户端程序员产生重大影响 -25.使用super可以访问从基类继承的方法和成员,前提是这些方法和成员是public、protected,或着父类和子类在同一个包内且不是private的。 -26.如果父类的构造器没有无参形式(由于用户自定义了带参构造器),子类的构造器需要手动调用super(para);如果存在,则自动调用super(); -27.如果需要保证一个行为一定被执行(例如一些清除操作,手动编写和调用而不应该依赖finalize()和GC),应该将该行为放在finally块中: - try{ - ... - }finally{ - //mustBeDone(); - } - 对于清除操作,如果被清除对象是派生类,则注意对其父类也调用清除操作,方式类似构造方法的构造链的,顺序相反,与C++的析构函数的方式相同。 -28.可以把 @ override放在重写方法之前,如果对父类的方法进行的重载而非重写,编译器会报错 -29.final关键字使用在数据、方法和类的意义不同。 - *final数据: - +对于基本类型,final使数值恒定不变;对于对象引用,final使对象引用不变,而对象本身是可以改变的 - -如数组对象,final int[] a = {1,2,3},a只能指向该数组,但1,2,3是可以修改的 - +static final标识的变量是编译期常量 - -如 final static int a = 1; - +final数据的两次初始化机会:定义处和构造器中。如果在定义处没有初始化,在构造器中必须初始化 - +final参数:在方法内不允许修改该参数变量的值 - *final方法: - +禁止该方法被重写,但可以使用,也即关闭动态绑定 - +在子类中声明一个跟父类private(final)方法同样的方法并不会产生重写效果 - +private方法都隐式的被指定为final方法,private方法并不作为父类接口的一部分,向上转型不能调用子类的同名方法(非覆盖),可能可以调用自身的private方法(如果在父类内部) - *final类:该类不能被继承 -30.多态的三种例外情况: - *private方法。如上所述,private方法被隐式的指定为final方法,因此也不存在重写的情况 - *域。同名的静态域被当成两个不同的数据空间,而不能进行“多态”,根据引用决定调用的目标 - *静态方法。与静态域类似,同名的静态方法会被当成两个不同的方法,没有“多态”,根据引用决定调用的目标 -31.在构造器里调用多态方法可能导致使用了未被正确初始化的变量,如在父类的构造器调用一个在子类中重写的方法,而该方法可能使用了一个子类中的非静态成员变量,该变量此时还未被正确赋值。 -32.Java SE5中添加了协变返回类型,这种机制允许子类重写方法返回父类被重写方法返回类型的派生类型,这样的形式同样被认为是多态的。 -33.包含abstract方法的类必是抽象类,抽象类不一定包含abstract方法(可能出于阻止产生该类对象的目的) -34.Interface的域默认的是static、final和public,方法默认为public。在实现Interface时,必须将实现接口的方法声明为public。接口也可以通过extends关键字来扩展接口 -35.使用Interface的理由 - *为实现多继承提供类似的实现,进而能够向上转型为多个基类型(以及由此带来的灵活性) - *空接口提供一个标签机制 - *多个不同的类型实现同一个接口,可以使得这些类能够向上转型为同一个基类型(例如作为方法的参数来实现策略设计模式,或是作为泛型容器的实现方式) -36.菱形继承问题:在Java中只有一个不合法的情况,即在一个类实现的两个接口中使用了完全一致的静态变量。使用同名函数能够正常工作。 -37.非静态内部类的创建需要捕获一个指向外围类的对象引用,因此不能脱离外围类对象创建内部类对象。内部类对象能访问器外围对象的所有成员,而且不需要任何特殊条件(即使为private),且嵌套层数不影响其对外围对象成员的访问,此外,内部类还拥有器外围类的所有元素的访问权。 -38.创建非静态内部类的两种方法: - *Outer out = new Outer(); - Outer.Inner in = out.createInner(); - *Outer out = new Outer(); - Outer.Inner in = out.new Inner(); - 不能是Outer.Inner in = new Inner();或者Outer.Inner in = out.new Outer.Inner(); -39.静态内部类(嵌套类)不需要对外部类对象的引用 -40.匿名内部类没有构造器,但可以使用非静态块达到实例初始化的目的。如果想在匿名内部类中使用外部方法的变量/参数,则要求这些变量/参数是final的。(传给基类构造器的使用不在此列) -41.匿名内部类只能实现一个接口或者继承一个基类(2选1) -42.为什么需要内部类:由于内部类可以继承自一个类且可以对外围类进行操作,这意味着多个内部类可以实现更为贴近真正意义上的多重继承,即允许继承多个非接口类型 -43.继承内部类B的派生类A必须提供一个以外部类C作为参数的构造器,并在A的构造器内调用c.super(); -44.通过对容器使用泛型,可以在编译期防止将错误类型对象放入容器中 -45.Object默认的toString()方法=类名+hashcode() -46.List,Set,Map都是实现了Collection接口的容器,其中 - *ArrayList和LinkedList维护插入顺序 - *HashSet维护乱序,TreeSet维护升序,LinkedHashSet维护插入顺序 - *HashMap维护乱序,TreeMap维护升序,LinkedHashMap维护插入顺序 -47.Java的迭代器跟C++类似,主要包括方法: - *collection.iterator();获得当前容器的迭代器,相当于C++的containter.begin(); - *collection.next();获取下一个迭代器位置,相当于C++的itr++; - *collection.hasNext();检查序列中是否还有元素,相当于itr!=container.end(); -48.继承Collection就必须实现iterator()方法,该方法要求返回一个Iterator< A >对象,可以使用匿名内部类方式返回该迭代器对象。 -49.如果想要在foreach中使用某种容器类型(除数组外),要求该容器实现Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,实现iterator()的方法可以参考48。一个好的例子见Thinking in Java P243 -50.使用Arrays.asList()需要谨慎,直接使用该方法返回的容器对象和使用该容器对象构造新的容器对象会产生不同的效果 - *Integer[] ia = {1, 2, 3}; - *List list1 = Array.asList(ia);//对list1的排序会影响ia数组 - *List list2 = new ArrayList(Array.asList(ia));//对list2的排序不会影响底层ia数组 -51.异常处理通常有两种理论模型:终止与恢复。但通常采用终止方法,因为恢复方法需要知道异常抛出地点信息,在大型程序中会增大代码编写和维护的困难。 -52.异常说明(必检异常)形如void f() throws Exception1, Exception2{...},在程序中手动/再次抛出异常使用throw ex1;。声明抛出异常的方法可以不抛出异常,只为占位。异常说明可能有两种意思:一是代码可能产生某些异常需要使用该方法的方法处理,二是代码忽略这些异常,这些异常由方法调用者处理。 -53.异常栈轨迹的栈顶是调用序列的最后一个方法,栈底是调用序列的第一个方法(通常为main())。 -54.如果把当前异常对象重新抛出,则printStackTrace()方法输出的仍然是原来抛出点的的信息,如果对当前异常对象调用fillInStackTrace()方法并抛出其返回的Throwable对象(Exception实现了Throwable接口),则异常栈顶会改写成当前方法。 -55.捕获异常对象后生成一个与之前异常无关的新异常对象,则与fillInStackTrace()效果类似。如果使用旧一场对象构造新异常对象,则构成异常链。 -56.RuntimeException及其任何派生类都属于免检异常,如果在异常的抛出全过程中都没有捕获免检异常的代码,则到达main()程序退出时会调用printStackTrace()。 -57.finally块应用的场合与finalize()不同,用于清理除内存外的其他系统资源占用,如已打开的文件和网络连接等。 -58.需要注意构造器中的异常处理,在处理完之后应该再次抛出以保证不会误导使用者。 -59.在生成需要清理对象阶段应该是try嵌套块来保证对象未生成抛出异常/对象生成了总是能被清理,如 - try{ - // create file - try{ - // do something - }catch(Exception e){ - // exception - }finally{ - // close file operation - } - }catch(Exception e){ - // create file failed - } -60.注意catch块的书写顺序,防止屏蔽现象。 -61.对于多次字符串累加操作,最好使用java.lang.StringBuilder来提高性能。如果需要线程安全特性,使用StringBuffer。 -62.重写toString()要小心无意识递归调用。String类的多数方法在没有改变原对象的情况下会返回原对象引用,改变了则返回新对象的引用。 -63.如果需要格式化输出,System.out.format()和System.out.printf()都可以提供C风格的格式输出,使用String.format()可以用C风格构造一个String对象。%(+-)width.precision type,正负号表示右对齐/左对齐,width表示输出宽度,precision表示输出精度,type表示输出类型。 -64.Java使用Class对象来执行其RTTI,每个.class文件都会有一个对应该类的Class对象,所有的类都是对其第一次使用时动态加载到JVM中的。原生类加载器会首先加载可信类(如Java API类)。当使用一个类时,类加载器首先检查这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件 -65.获取Class对象引用的两种方式:Class.forName()和A.class,前者是Class的静态方法,会触发类的加载;后者是类A的static和final的编译器常量,不会触发类的加载。 -66.可以使用classobj.newInstance()来生成一个新的对象,注意该类必须具有默认构造函数。如果classobj是一个Class对象,则newInstance可以返回一个Type对象,如果classobj是一个Class对象,则返回一个Object对象。 -67.RTTI的另一个种形式是使用instanceof关键字,语法 obj instance classname ,返回值为boolean。instanceof方式检测了所有可能,包括当前类及其派生类,而使用Class对象比较仅检测了当前类是否相等的情况。 -68.反射也必须建立在JVM能够获知当前处理的对象的类型的基础之上,Class与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了、Method已经Constructor类(每个类都实现了Member接口) -69.RTTI和反射之间真正的区别只在于,RTTI是编译器在编译时打开和检查.class,反射是.class在编译时是不可获取,运行时打开和检查文件。 -70.RTTI带来的副作用之一是破坏了API提供者想通过Interface来控制客户端程序员访问权限的机会,客户端程序员可以通过向下转型访问到本不属于接口内的方法,使得这部分的API也成为事实上的公共接口,增大了维护成本。 -71.动态代理:在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是解释调用的类型并确定相应的对策。原理总结: - *代理类和被代理类实现同一个(或多个)接口InterfaceX - *DynamicProxyHandler类实现接口InvocationHandler,并持有一个被代理类的对象,主要通过invoke()方法来联结代理对象和被代理对象 - *java.lang.reflect.Proxy类的newProxyInstance()方法可以动态生成代理对象,该方法的三个参数分别是类加载器,接口列表和Handler对象 - *e.g. InterfaceX proxy = (InterfaceX)Proxy.newProxyInstance(InterfaceX.class.getClassLoader(),new Class[] {InterfaceX.class}, new DynamicProxyHandler(proxied)); -72.泛型类与泛型方法: - *是否是泛型类和是否有泛型方法没有必然联系,但static方法要使用泛型能力必须使自己成为泛型方法 - *使用泛型类时必须显式的指定类型参数,而使用泛型方法则不用,编译器会自动进行参数类型推断 - *泛型类只需要在类名后用<>指定参数类型,泛型方法除了在参数/返回值里使用<>指定参数类型,而且在返回值之前也要用<>指定参数类型 -73.泛型擦除:在泛型代码内部,无法获得任何有关泛型参数类型的信息,在使用泛型时任何具体类型信息都被擦除,List和List在运行时事实上是相同的类型,都被擦除成相同类型List,尽管如此,编译器可以确保方法或类中使用的类型的内部一致性。 - *Class c1 = new ArrayList().getClass(); - *Class c2 = new ArrayList().getClass(); - *c1 == c2 为 true -74.无法在对泛型进行的操作:instanceof,new,转型(将T转型为其他类型),因为类型擦除导致类型信息丢失,但可以使用Class对象用newInstance()方法创建对象。创建数组可以通过 T[] array = (T[])new Object[size];进行,切记array在运行时类型只能是Object[] -75.Arrays使用方法,equals()比较相等,fill()填充,sort()排序,binarySearch()在排序数组中查找,toString(),hashcode()。此外还有System.arraycopy(),这种拷贝方式比用for快很多。 -76.通过实现java.lang.Comparable接口可以让容器和数组的sort()对自定义类进行排序,需要实现campareTo()方法 -77.Object使用对象的地址作为hashcode()和equals ()的默认实现。如果要使用自己的类作为HashMap的键,必须同时重载hashCode()和equals()方法。 -78.equals()决定了在链式冲突中寻找唯一对象的标准。equals()的重载方法 - public boolean equals(Object o){ - return o instance of Type && (member1 == ((Type)o).member1)&&..&&(memberk == ((Type)o).memberk) - } -79.hashcode()的重载方法 - public int hashCode(){ - int result = 17; - result = result * 37 + member1.hashCode(); - result = result * 37 + c(member2); - result = result * 37 + c(memberk); - } - 其中c()是对基本类型的整数化操作。 -85.File类不仅仅指单一文件名称,也可能是一个文件集合 -86.System.out和System.err已经被包装成PrintStream对象,因此可以直接输出,但System.in还是原始的InputStream,因此需要输入包装类才能使其正常工作,如BufferReader in = new BufferReader(new InputStreamReader(System.in)); -87.System.setIn(InputStream), System.setOut(PrintStream)和System.setErr(PrintStream)可以重定向标准输入/输出流 -88.对于文件流对象,可以调用FileLock fl = ((FileOuputStream)fos).getChannel().tryLock();注意tryLock()是非阻塞方法,而lock()是阻塞方法,release()可以释放锁。 -89. 一般的序列化需求就实现Serializable接口,如果是需要自己控制序列化过程则实现Externalizable接口。transient关键字可以用于不想被序列化的类成员之前防止被序列化。 -90.Java的线程机制是抢占式的(但协作式有着更小的代价)。实现一个线程类 - public class A implements Runnable{ - // Constructer omit - public void run(){ - // Do something - Thread.yeild();//通知线程调度器自己任务已经完成(可选) - } - } -但是一个实现Runnable接口的类并不具有产生线程的能力,要实现线程行为,必须显式地将一个任务附在线程上。具体做法是使用Runnable对象作为参数生成一个Tread对象,再调用Thread对象的start()方法,该方法是一个非阻塞方法,启动线程后立即返回。如果直接调用Runnable的run()方法,则会阻塞调用线程(如main线程)。 -91.Java提供线程池ExecutorService类,创建一个线程池的代码如下 - ExecutorService exec1 = Executors.newCachedTreadPool();//创建一个大小可变的线程池,合理的首选 - ExecutorService exec2 = Executors.newFixedTreadPool(5);//创建一个固定大小的线程池,一次性执行线程分配,效率高 - ExecutorService exec3 = Executors.newSingleTreadPool();//创建大小为1的线程池,可以提交多个线程,但线程会排队,用于socket监听类任务 - 提交线程任务 - exec1.execute(new A());//A是90中提到的Runnable实现类 - 阻止一个线程池继续工作的方法 - exec1.shutdown();//无法继续提交新的线程任务,旧的会继续执行完毕 -92.通过Tread.currentThread()可以获得当前执行线程的对象引用。JDK有10个进程优先级,而Windows有7个优先级且不是固定的。 -93.线程分为后台线程和非后台线程,后台线程往往是提供通用服务的线程,不属于不可获取的部分,非后台线程反之,如main线程。当所有非后台线程结束工作时,程序终止,后台线程会立即被终止,即使finally也不能得到保证(非后台线程的finally一定会执行)。 -94.通过把方法标记为synchronized来防止资源冲突,如方法f()和g()都会对某个关键资源操作,则加上synchronized关键字 - synchronized void f(){} - synchronized void g(){} -所有对象都含有单一的锁,对于某个特定的对象,所有的synchronized方法共享一个锁,事实上等同synchronized(this),一个synchronized方法被调用,其他线程便不能调用其他synchronized方法。在使用并发时,将域设置为private非常重要,否则synchronized关键字不能防止其他任务直接访问域,进而产生冲突。 -95.JVM负责跟踪对象的加锁次数,一个任务可以多次获得对象的锁。如果一个方法又调用了自身的一个同步方法,则加速次数加1,一个对象被解锁当且仅当其加锁计数减为0。针对每个类也有一个锁,对static方法适用synchronized关键字可以防止静态方法冲突。 -96.可以使用synchronized(otherObject)来实现互斥,但要保证所有使用同一个关键资源的代码块在同一个对象上加锁。 -97.使用java.util.concurrent.locks类实现互斥,相比使用synchronized关键字能够实现更加灵活,粒度更细的加锁 - Lock lock = new ReentrantLock(); - lock.lock(); - try{ - // Do something - return; - }finally{ - lock.unlock(); - } -98.volatile关键字可以让域得到立即更新,因而同步性得到一定保障,如果一个域完全被synchronized包括,则不必使用volatile。 -99.线程状态: - *新建(new):已被分配资源且初始化,等待调度 - *就绪(runnable):只要调度就可运行 - *阻塞(blocked):因某个条件被阻止运行,调度器忽略此线程 - *死亡(dead):不可运行 -100.造成阻塞的原因包括 - *sleep()休眠,可以中断 - *wait()挂起,等待notify()或notifyAll()方法,在挂起期间锁会被释放 - *等待IO,不可中断 - *试图获得锁但未成功,不可中断 -101.向持有某对象锁的所有线程发送通知 - synchronized(x){ - x.notifyAll();//所有等待线程竞争该锁 - //x.notify; 仅通知单一线程来获取该锁 - } -102.生产者消费者代码示例见Thinking in java P709 -103.如果使用BlockingQueue和PriorityBlockingQueue可以直接使用put()和take()方法而不同担心手动同步问题,容器已经在内部同步。 -104.产生死锁的四个必要条件 - *互斥条件,即使用的资源中至少有一个不能共享 - *等待,即至少有一个线程掌握一部分资源的同时等待另外一些资源 - *资源不能被抢占,即只能等待别人释放 - *循环等待 -只需要破坏一个即可阻止死锁 -105.正常的锁(来自concurrent.locks或内建的synchronized锁)在任何时刻都只允许一个任务访问一项资源,而Semaphore则允许n个线程同时访问这个资源 - Semaphore sem = new Semaphore(size, true); - sem.acquire(); - sem.release(); -106.线程相对与进程更加轻量级,切换仅需要100条左右的指令,而进程需要上千条,同时进程需要切换上下文,而线程只需要改变程序的执行序列和局部变量。 -107.线程的缺陷: - *等待临界资源时效率降低 - *处理线程带来的额外CPU开销 - *增加了程序的复杂度 - *有可能产生病态行为,如饿死,竞争,死锁,活锁(多个线程各自运行导致无法完成整体任务)等 - *平台不一致性 - -注:由于时间原因和过于复杂的内容跳过泛型一章P389页之后的内容、枚举类型一章,注解一章的内容,以后补完。 - diff --git a/Basic Algorithm & Data Structure.md b/Basic Algorithm & Data Structure.md index 7a37996..144098c 100644 --- a/Basic Algorithm & Data Structure.md +++ b/Basic Algorithm & Data Structure.md @@ -4,6 +4,7 @@ Index: -[Heap Sort](#Anchor1) -[Union Find Sets](#Anchor2) -[Nonrecursive Tree Traversal](#Anchor3) +-[KMP](#Anchor4) ------- @@ -144,4 +145,62 @@ void postOrderTraversalNonRecursive(TreeNode * root){ if(stk.empty()) return; } } +``` + +------- + +-**KMP**([Back to Index](#AnchorIndex)) +KMP算法,首先要算出字符串的覆盖数组,当发生在j长度失配时,只要把pattern向右移动j-overlay(j)长度就可以了。 + +```cpp +#include +#include +#include +using namespace std; + +int kmp_find(const string& target, const string& pattern) { + const int target_length = target.size(); + const int pattern_length = pattern.size(); + int * overlay_value = new int[pattern_length]; + overlay_value[0] = -1; + int index = 0; + for (int i = 1; i < pattern_length; ++i) { + index = overlay_value[i - 1]; + while (index >= 0 && pattern[index + 1] != pattern[i]) { + index = overlay_value[index]; + } + if (pattern[index + 1] == pattern[i]) { + overlay_value[i] = index + 1; + } else { + overlay_value[i] = -1; + } + } + //match algorithm start + int pattern_index = 0; + int target_index = 0; + while (pattern_index < pattern_length && target_index < target_length) { + if (target[target_index] == pattern[pattern_index]) { + ++target_index; + ++pattern_index; + } else if (pattern_index == 0) { + ++target_index; + } else { + pattern_index = overlay_value[pattern_index - 1] + 1; + } + } + if (pattern_index == pattern_length) { + return target_index - pattern_index; + } else { + return -1; + } + delete [] overlay_value; +} + +int main() { + string source = " annbcdanacadsannannabnna"; + string pattern = " annacanna"; + cout << kmp_find(source, pattern) << endl; + return 0; +} + ``` \ No newline at end of file diff --git a/Basic Java Concepts.md b/Basic Java Concepts.md index 7951def..cd18f55 100644 --- a/Basic Java Concepts.md +++ b/Basic Java Concepts.md @@ -1 +1,289 @@ -NULL +##Basic Java Concepts + +本章列举了一些较为重要和较难记忆理解的Java知识收录此处共查阅学习,如有谬误,欢迎发送pull request。 + + +Index: +-[与C++的一些不同之处](#Anchor1) +-[](#Anchor2) + +------- + +-**[与C++的一些不同之处]**([Back to Index](#AnchorIndex)) + +1.char类型的宽度为16bit;c++为8bit +2.没有unsigned修饰符;c++有 +3.下列代码是非法的;c++合法 +```cpp + int x = 12; + { + int x = 13; + } +``` +4.String s;并没有创建一个对象,只是声明了一个引用;c++在栈上创建了一个对象 +5.类成员会获得默认值;c++不会自动初始化类成员 +6.类成员可以直接初始化;c++的类成员不能直接初始化,可以在构造函数里初始化 +7.对于对象参数,默认为传引用;c++默认为传值 +8.=号赋值只是使新的引用指向了旧的对象,也即新旧引用指向同一个对象;c++则会生成一个新的对象 +9.>>>号是高位补0右移运算符;c++无此符号 +10.拥有finalize()方法;c++只有析构函数 +11.可以使用int[] A或int A[]方式声明一个数组,因为是引用,不可以指定数组大小;c++只能使用int A[]的方式,可以指定数组大小 +12.默认开启动态绑定;C++使用virtual关键字才能开启动态绑定 +13.所有容器都有共同的基类Collection;C++容器之间没有共同的基类,依赖迭代器达成共性 +14.泛型和模板对比: + >*C++模板在编译期检查对模板对象的调用是否在该对象所属类总存在来保证类型安全 + >*Java由于采用了类型擦除,仅使用T会使对象所属类被擦除到Object,而非其真正所属类,因此也就无法验证调用是否合法,因此要使用T extends Type来表示泛型边界(一个好的例子见Thinking in Java P375) +15.Comparable接口的方法compareTo(Type obj)返回的值包括-1,0,1,分别表示当前对象小于,等于,大于参数obj; + C++的比较函数cmp(Type obj1, Type obj2)则只返回true和false,obj1<=obj2返回true,反之返回false + +------- + +-**[与C++的一些不同之处]**([Back to Index](#AnchorIndex)) + +###*Java重要知识点 +1.java.lang是默认导入每个java文件的 +2.equals()默认行为是比较引用,可以重写;==判断的是引用的内存地址是否相同 +3.对byte和short的位移操作要特别小心,它们会被转换为int型然后位移,这会导致不正确的结果 +4.bool类型不允许任何类型转换,也不允许使用类似while(1)的语句,0,1并不等同于false和true,必须使用while(true) +5.float或double转为整形值时,总是对该数字进行截尾 +6.提升:对基本数据类型进行算术运算或按位运算时,低于int型的数据类型(char、byte和short)总是会先转换为int再运算;数据类型大的类型决定了结果的类型 +7.不能仅仅使用返回值不同的方法作为重载方法,应该使参数列表不同(至少是顺序不同) +8.如果已经定义了一个构造器,无论是否有参数,编译器不会自动创建默认构造器 +9.this的三个应用场合: + *用于引用自身对象的成员,特别是因为成员与方法参数重名 + *用于在一个重载的构造器中调用另一个构造器,此时必须放在第一句,且只有构造器可以调用其他构造器 + *用于返回自身对象的引用 +10.被static修饰的方法内不能调用非static方法和成员,因为非static方法和成员依赖具体的对象(除非这个静态方法获得自身类的一个对象实例并通过该实例调用非晶态方法) +11.Java没有C++的析构函数,取而代之是finalize(),用于释放非Java代码(如native C)申请的系统资源,由GC调用(不要直接调用finalize()方法),而GC的调用时机是不能被预期的。 +12.Java的GC机制包括两种:"停止-复制"和“标记-清扫”,都是从堆栈和静态存储区开始扫描引用。采用自适应技术在两种技术中切换,碎片多时用“停止-复制”,碎片少时用“标记-清扫”。 +13.不同于类成员,局部变量必须被初始化,否则报错。 +14.类成员的初始化顺序:类加载->new操作(或访问静态域,此行为不会导致空间分配)->静态成员初始化(包括静态块)(只发生一次,如果以前new操作/访问静态域操作出现过则不再初始化)->分配空间,非静态成员初始化(包括非静态块)->构造方法。类成员变量的初始化(包括但不限于默认初始化行为)绝对先于构造器的对类成员的初始化操作。 + 一个继承自A类的B类对象的初始化顺序:类B加载->类A加载->类A的静态成员初始化->类B的静态成员初始化->类A非静态成员初始化->类A的构造方法->类B非静态成员初始化->类B的构造方法 +15.构造器是static方法。 +16.一下两种声明和初始化数组的方式都是合法的,最后一个逗号是可选的 + *Integer[] a = {new Integer(1), new Integer(2), 3, }//Auto Boxing + *Integer[] b = new Integer[]{new Integer(1), new Integer(2), 3, }//Auto Boxing +17.可变参数形如void function(type... args),三个注意点: + *可以给可变参数列表传0个参数 + *可变参数列表不依赖于Auto Boxing + *尽量避免在多个重载方法中使用可变参数,可能会引起歧义 + void function(int a, int... args){} + void function(int... args){} + *如果必须使用,添加非可变参数如 + void function(int a, int... args){} + void function(string b, int... args){} +18.enum的使用跟类相近,可以使用在switch内。可以对一个enum对象赋予枚举类型值,如EnumType et = EnumType.type1 +19.一个Java源文件中最多只能有一个public类,当有一个public类时,源文件名必须与之一致,否则无法编译,如果源文件中没有一个public类,则文件名与类中没有一致性要求。至于main()不是必须要放在public类中才能运行程序。总结出如下4点 + *Java源文件可以有public类,也可以没有 + *如果有public类,则该public类必须与文件名同名 + *如果没有public类,则不要求有与文件名同名的类 + *main()方法的放在哪个类里没有硬性要求,跟是否在public类中也没有关系,一个文件中多个类可以各自持有一个main()方法,都可以用java命令运行 +20.Java解释器的运行过程是首先找出环境变量CLASSPATH用于查找.class的根目录,然后加载。 +21.访问权限控制的等级:public->protected->包访问权限->private +22.类的权限控制的等级:public->包访问权限,不可以是protected或private的 +23.一个类的构造器是private的,任何其他类无法直接创建该类,只有该类的static方法或对static对象赋值(即非延迟化实现)才可以创建一个该类的对象 +24.使用成员的访问控制主要有两个原因: + *使用户不要碰触他们不该碰触的部分 + *更重要的是,可以让类的设计者改变类的内部实现而不影响会对客户端程序员产生重大影响 +25.使用super可以访问从基类继承的方法和成员,前提是这些方法和成员是public、protected,或着父类和子类在同一个包内且不是private的。 +26.如果父类的构造器没有无参形式(由于用户自定义了带参构造器),子类的构造器需要手动调用super(para);如果存在,则自动调用super(); +27.如果需要保证一个行为一定被执行(例如一些清除操作,手动编写和调用而不应该依赖finalize()和GC),应该将该行为放在finally块中: + try{ + ... + }finally{ + //mustBeDone(); + } + 对于清除操作,如果被清除对象是派生类,则注意对其父类也调用清除操作,方式类似构造方法的构造链的,顺序相反,与C++的析构函数的方式相同。 +28.可以把 @ override放在重写方法之前,如果对父类的方法进行的重载而非重写,编译器会报错 +29.final关键字使用在数据、方法和类的意义不同。 + *final数据: + +对于基本类型,final使数值恒定不变;对于对象引用,final使对象引用不变,而对象本身是可以改变的 + -如数组对象,final int[] a = {1,2,3},a只能指向该数组,但1,2,3是可以修改的 + +static final标识的变量是编译期常量 + -如 final static int a = 1; + +final数据的两次初始化机会:定义处和构造器中。如果在定义处没有初始化,在构造器中必须初始化 + +final参数:在方法内不允许修改该参数变量的值 + *final方法: + +禁止该方法被重写,但可以使用,也即关闭动态绑定 + +在子类中声明一个跟父类private(final)方法同样的方法并不会产生重写效果 + +private方法都隐式的被指定为final方法,private方法并不作为父类接口的一部分,向上转型不能调用子类的同名方法(非覆盖),可能可以调用自身的private方法(如果在父类内部) + *final类:该类不能被继承 +30.多态的三种例外情况: + *private方法。如上所述,private方法被隐式的指定为final方法,因此也不存在重写的情况 + *域。同名的静态域被当成两个不同的数据空间,而不能进行“多态”,根据引用决定调用的目标 + *静态方法。与静态域类似,同名的静态方法会被当成两个不同的方法,没有“多态”,根据引用决定调用的目标 +31.在构造器里调用多态方法可能导致使用了未被正确初始化的变量,如在父类的构造器调用一个在子类中重写的方法,而该方法可能使用了一个子类中的非静态成员变量,该变量此时还未被正确赋值。 +32.Java SE5中添加了协变返回类型,这种机制允许子类重写方法返回父类被重写方法返回类型的派生类型,这样的形式同样被认为是多态的。 +33.包含abstract方法的类必是抽象类,抽象类不一定包含abstract方法(可能出于阻止产生该类对象的目的) +34.Interface的域默认的是static、final和public,方法默认为public。在实现Interface时,必须将实现接口的方法声明为public。接口也可以通过extends关键字来扩展接口 +35.使用Interface的理由 + *为实现多继承提供类似的实现,进而能够向上转型为多个基类型(以及由此带来的灵活性) + *空接口提供一个标签机制 + *多个不同的类型实现同一个接口,可以使得这些类能够向上转型为同一个基类型(例如作为方法的参数来实现策略设计模式,或是作为泛型容器的实现方式) +36.菱形继承问题:在Java中只有一个不合法的情况,即在一个类实现的两个接口中使用了完全一致的静态变量。使用同名函数能够正常工作。 +37.非静态内部类的创建需要捕获一个指向外围类的对象引用,因此不能脱离外围类对象创建内部类对象。内部类对象能访问器外围对象的所有成员,而且不需要任何特殊条件(即使为private),且嵌套层数不影响其对外围对象成员的访问,此外,内部类还拥有器外围类的所有元素的访问权。 +38.创建非静态内部类的两种方法: + *Outer out = new Outer(); + Outer.Inner in = out.createInner(); + *Outer out = new Outer(); + Outer.Inner in = out.new Inner(); + 不能是Outer.Inner in = new Inner();或者Outer.Inner in = out.new Outer.Inner(); +39.静态内部类(嵌套类)不需要对外部类对象的引用 +40.匿名内部类没有构造器,但可以使用非静态块达到实例初始化的目的。如果想在匿名内部类中使用外部方法的变量/参数,则要求这些变量/参数是final的。(传给基类构造器的使用不在此列) +41.匿名内部类只能实现一个接口或者继承一个基类(2选1) +42.为什么需要内部类:由于内部类可以继承自一个类且可以对外围类进行操作,这意味着多个内部类可以实现更为贴近真正意义上的多重继承,即允许继承多个非接口类型 +43.继承内部类B的派生类A必须提供一个以外部类C作为参数的构造器,并在A的构造器内调用c.super(); +44.通过对容器使用泛型,可以在编译期防止将错误类型对象放入容器中 +45.Object默认的toString()方法=类名+hashcode() +46.List,Set,Map都是实现了Collection接口的容器,其中 + *ArrayList和LinkedList维护插入顺序 + *HashSet维护乱序,TreeSet维护升序,LinkedHashSet维护插入顺序 + *HashMap维护乱序,TreeMap维护升序,LinkedHashMap维护插入顺序 +47.Java的迭代器跟C++类似,主要包括方法: + *collection.iterator();获得当前容器的迭代器,相当于C++的containter.begin(); + *collection.next();获取下一个迭代器位置,相当于C++的itr++; + *collection.hasNext();检查序列中是否还有元素,相当于itr!=container.end(); +48.继承Collection就必须实现iterator()方法,该方法要求返回一个Iterator< A >对象,可以使用匿名内部类方式返回该迭代器对象。 +49.如果想要在foreach中使用某种容器类型(除数组外),要求该容器实现Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,实现iterator()的方法可以参考48。一个好的例子见Thinking in Java P243 +50.使用Arrays.asList()需要谨慎,直接使用该方法返回的容器对象和使用该容器对象构造新的容器对象会产生不同的效果 + *Integer[] ia = {1, 2, 3}; + *List list1 = Array.asList(ia);//对list1的排序会影响ia数组 + *List list2 = new ArrayList(Array.asList(ia));//对list2的排序不会影响底层ia数组 +51.异常处理通常有两种理论模型:终止与恢复。但通常采用终止方法,因为恢复方法需要知道异常抛出地点信息,在大型程序中会增大代码编写和维护的困难。 +52.异常说明(必检异常)形如void f() throws Exception1, Exception2{...},在程序中手动/再次抛出异常使用throw ex1;。声明抛出异常的方法可以不抛出异常,只为占位。异常说明可能有两种意思:一是代码可能产生某些异常需要使用该方法的方法处理,二是代码忽略这些异常,这些异常由方法调用者处理。 +53.异常栈轨迹的栈顶是调用序列的最后一个方法,栈底是调用序列的第一个方法(通常为main())。 +54.如果把当前异常对象重新抛出,则printStackTrace()方法输出的仍然是原来抛出点的的信息,如果对当前异常对象调用fillInStackTrace()方法并抛出其返回的Throwable对象(Exception实现了Throwable接口),则异常栈顶会改写成当前方法。 +55.捕获异常对象后生成一个与之前异常无关的新异常对象,则与fillInStackTrace()效果类似。如果使用旧一场对象构造新异常对象,则构成异常链。 +56.RuntimeException及其任何派生类都属于免检异常,如果在异常的抛出全过程中都没有捕获免检异常的代码,则到达main()程序退出时会调用printStackTrace()。 +57.finally块应用的场合与finalize()不同,用于清理除内存外的其他系统资源占用,如已打开的文件和网络连接等。 +58.需要注意构造器中的异常处理,在处理完之后应该再次抛出以保证不会误导使用者。 +59.在生成需要清理对象阶段应该是try嵌套块来保证对象未生成抛出异常/对象生成了总是能被清理,如 + try{ + // create file + try{ + // do something + }catch(Exception e){ + // exception + }finally{ + // close file operation + } + }catch(Exception e){ + // create file failed + } +60.注意catch块的书写顺序,防止屏蔽现象。 +61.对于多次字符串累加操作,最好使用java.lang.StringBuilder来提高性能。如果需要线程安全特性,使用StringBuffer。 +62.重写toString()要小心无意识递归调用。String类的多数方法在没有改变原对象的情况下会返回原对象引用,改变了则返回新对象的引用。 +63.如果需要格式化输出,System.out.format()和System.out.printf()都可以提供C风格的格式输出,使用String.format()可以用C风格构造一个String对象。%(+-)width.precision type,正负号表示右对齐/左对齐,width表示输出宽度,precision表示输出精度,type表示输出类型。 +64.Java使用Class对象来执行其RTTI,每个.class文件都会有一个对应该类的Class对象,所有的类都是对其第一次使用时动态加载到JVM中的。原生类加载器会首先加载可信类(如Java API类)。当使用一个类时,类加载器首先检查这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件 +65.获取Class对象引用的两种方式:Class.forName()和A.class,前者是Class的静态方法,会触发类的加载;后者是类A的static和final的编译器常量,不会触发类的加载。 +66.可以使用classobj.newInstance()来生成一个新的对象,注意该类必须具有默认构造函数。如果classobj是一个Class对象,则newInstance可以返回一个Type对象,如果classobj是一个Class对象,则返回一个Object对象。 +67.RTTI的另一个种形式是使用instanceof关键字,语法 obj instance classname ,返回值为boolean。instanceof方式检测了所有可能,包括当前类及其派生类,而使用Class对象比较仅检测了当前类是否相等的情况。 +68.反射也必须建立在JVM能够获知当前处理的对象的类型的基础之上,Class与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了、Method已经Constructor类(每个类都实现了Member接口) +69.RTTI和反射之间真正的区别只在于,RTTI是编译器在编译时打开和检查.class,反射是.class在编译时是不可获取,运行时打开和检查文件。 +70.RTTI带来的副作用之一是破坏了API提供者想通过Interface来控制客户端程序员访问权限的机会,客户端程序员可以通过向下转型访问到本不属于接口内的方法,使得这部分的API也成为事实上的公共接口,增大了维护成本。 +71.动态代理:在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是解释调用的类型并确定相应的对策。原理总结: + *代理类和被代理类实现同一个(或多个)接口InterfaceX + *DynamicProxyHandler类实现接口InvocationHandler,并持有一个被代理类的对象,主要通过invoke()方法来联结代理对象和被代理对象 + *java.lang.reflect.Proxy类的newProxyInstance()方法可以动态生成代理对象,该方法的三个参数分别是类加载器,接口列表和Handler对象 + *e.g. InterfaceX proxy = (InterfaceX)Proxy.newProxyInstance(InterfaceX.class.getClassLoader(),new Class[] {InterfaceX.class}, new DynamicProxyHandler(proxied)); +72.泛型类与泛型方法: + *是否是泛型类和是否有泛型方法没有必然联系,但static方法要使用泛型能力必须使自己成为泛型方法 + *使用泛型类时必须显式的指定类型参数,而使用泛型方法则不用,编译器会自动进行参数类型推断 + *泛型类只需要在类名后用<>指定参数类型,泛型方法除了在参数/返回值里使用<>指定参数类型,而且在返回值之前也要用<>指定参数类型 +73.泛型擦除:在泛型代码内部,无法获得任何有关泛型参数类型的信息,在使用泛型时任何具体类型信息都被擦除,List和List在运行时事实上是相同的类型,都被擦除成相同类型List,尽管如此,编译器可以确保方法或类中使用的类型的内部一致性。 + *Class c1 = new ArrayList().getClass(); + *Class c2 = new ArrayList().getClass(); + *c1 == c2 为 true +74.无法在对泛型进行的操作:instanceof,new,转型(将T转型为其他类型),因为类型擦除导致类型信息丢失,但可以使用Class对象用newInstance()方法创建对象。创建数组可以通过 T[] array = (T[])new Object[size];进行,切记array在运行时类型只能是Object[] +75.Arrays使用方法,equals()比较相等,fill()填充,sort()排序,binarySearch()在排序数组中查找,toString(),hashcode()。此外还有System.arraycopy(),这种拷贝方式比用for快很多。 +76.通过实现java.lang.Comparable接口可以让容器和数组的sort()对自定义类进行排序,需要实现campareTo()方法 +77.Object使用对象的地址作为hashcode()和equals ()的默认实现。如果要使用自己的类作为HashMap的键,必须同时重载hashCode()和equals()方法。 +78.equals()决定了在链式冲突中寻找唯一对象的标准。equals()的重载方法 + public boolean equals(Object o){ + return o instance of Type && (member1 == ((Type)o).member1)&&..&&(memberk == ((Type)o).memberk) + } +79.hashcode()的重载方法 + public int hashCode(){ + int result = 17; + result = result * 37 + member1.hashCode(); + result = result * 37 + c(member2); + result = result * 37 + c(memberk); + } + 其中c()是对基本类型的整数化操作。 +85.File类不仅仅指单一文件名称,也可能是一个文件集合 +86.System.out和System.err已经被包装成PrintStream对象,因此可以直接输出,但System.in还是原始的InputStream,因此需要输入包装类才能使其正常工作,如BufferReader in = new BufferReader(new InputStreamReader(System.in)); +87.System.setIn(InputStream), System.setOut(PrintStream)和System.setErr(PrintStream)可以重定向标准输入/输出流 +88.对于文件流对象,可以调用FileLock fl = ((FileOuputStream)fos).getChannel().tryLock();注意tryLock()是非阻塞方法,而lock()是阻塞方法,release()可以释放锁。 +89. 一般的序列化需求就实现Serializable接口,如果是需要自己控制序列化过程则实现Externalizable接口。transient关键字可以用于不想被序列化的类成员之前防止被序列化。 +90.Java的线程机制是抢占式的(但协作式有着更小的代价)。实现一个线程类 + public class A implements Runnable{ + // Constructer omit + public void run(){ + // Do something + Thread.yeild();//通知线程调度器自己任务已经完成(可选) + } + } +但是一个实现Runnable接口的类并不具有产生线程的能力,要实现线程行为,必须显式地将一个任务附在线程上。具体做法是使用Runnable对象作为参数生成一个Tread对象,再调用Thread对象的start()方法,该方法是一个非阻塞方法,启动线程后立即返回。如果直接调用Runnable的run()方法,则会阻塞调用线程(如main线程)。 +91.Java提供线程池ExecutorService类,创建一个线程池的代码如下 + ExecutorService exec1 = Executors.newCachedTreadPool();//创建一个大小可变的线程池,合理的首选 + ExecutorService exec2 = Executors.newFixedTreadPool(5);//创建一个固定大小的线程池,一次性执行线程分配,效率高 + ExecutorService exec3 = Executors.newSingleTreadPool();//创建大小为1的线程池,可以提交多个线程,但线程会排队,用于socket监听类任务 + 提交线程任务 + exec1.execute(new A());//A是90中提到的Runnable实现类 + 阻止一个线程池继续工作的方法 + exec1.shutdown();//无法继续提交新的线程任务,旧的会继续执行完毕 +92.通过Tread.currentThread()可以获得当前执行线程的对象引用。JDK有10个进程优先级,而Windows有7个优先级且不是固定的。 +93.线程分为后台线程和非后台线程,后台线程往往是提供通用服务的线程,不属于不可获取的部分,非后台线程反之,如main线程。当所有非后台线程结束工作时,程序终止,后台线程会立即被终止,即使finally也不能得到保证(非后台线程的finally一定会执行)。 +94.通过把方法标记为synchronized来防止资源冲突,如方法f()和g()都会对某个关键资源操作,则加上synchronized关键字 + synchronized void f(){} + synchronized void g(){} +所有对象都含有单一的锁,对于某个特定的对象,所有的synchronized方法共享一个锁,事实上等同synchronized(this),一个synchronized方法被调用,其他线程便不能调用其他synchronized方法。在使用并发时,将域设置为private非常重要,否则synchronized关键字不能防止其他任务直接访问域,进而产生冲突。 +95.JVM负责跟踪对象的加锁次数,一个任务可以多次获得对象的锁。如果一个方法又调用了自身的一个同步方法,则加速次数加1,一个对象被解锁当且仅当其加锁计数减为0。针对每个类也有一个锁,对static方法适用synchronized关键字可以防止静态方法冲突。 +96.可以使用synchronized(otherObject)来实现互斥,但要保证所有使用同一个关键资源的代码块在同一个对象上加锁。 +97.使用java.util.concurrent.locks类实现互斥,相比使用synchronized关键字能够实现更加灵活,粒度更细的加锁 + Lock lock = new ReentrantLock(); + lock.lock(); + try{ + // Do something + return; + }finally{ + lock.unlock(); + } +98.volatile关键字可以让域得到立即更新,因而同步性得到一定保障,如果一个域完全被synchronized包括,则不必使用volatile。 +99.线程状态: + *新建(new):已被分配资源且初始化,等待调度 + *就绪(runnable):只要调度就可运行 + *阻塞(blocked):因某个条件被阻止运行,调度器忽略此线程 + *死亡(dead):不可运行 +100.造成阻塞的原因包括 + *sleep()休眠,可以中断 + *wait()挂起,等待notify()或notifyAll()方法,在挂起期间锁会被释放 + *等待IO,不可中断 + *试图获得锁但未成功,不可中断 +101.向持有某对象锁的所有线程发送通知 + synchronized(x){ + x.notifyAll();//所有等待线程竞争该锁 + //x.notify; 仅通知单一线程来获取该锁 + } +102.生产者消费者代码示例见Thinking in java P709 +103.如果使用BlockingQueue和PriorityBlockingQueue可以直接使用put()和take()方法而不同担心手动同步问题,容器已经在内部同步。 +104.产生死锁的四个必要条件 + *互斥条件,即使用的资源中至少有一个不能共享 + *等待,即至少有一个线程掌握一部分资源的同时等待另外一些资源 + *资源不能被抢占,即只能等待别人释放 + *循环等待 +只需要破坏一个即可阻止死锁 +105.正常的锁(来自concurrent.locks或内建的synchronized锁)在任何时刻都只允许一个任务访问一项资源,而Semaphore则允许n个线程同时访问这个资源 + Semaphore sem = new Semaphore(size, true); + sem.acquire(); + sem.release(); +106.线程相对与进程更加轻量级,切换仅需要100条左右的指令,而进程需要上千条,同时进程需要切换上下文,而线程只需要改变程序的执行序列和局部变量。 +107.线程的缺陷: + *等待临界资源时效率降低 + *处理线程带来的额外CPU开销 + *增加了程序的复杂度 + *有可能产生病态行为,如饿死,竞争,死锁,活锁(多个线程各自运行导致无法完成整体任务)等 + *平台不一致性 + +注:由于时间原因和过于复杂的内容跳过泛型一章P389页之后的内容、枚举类型一章,注解一章的内容,以后补完。 + From f5dc623efd66e5236b7f506f137834d60ce4502e Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 28 Oct 2014 22:57:03 +0800 Subject: [PATCH 300/327] merging --- ...tions$keywords Permutation, Combination.md | 334 ------------------ Array & String.md | 75 +++- README.md | 7 +- 3 files changed, 78 insertions(+), 338 deletions(-) delete mode 100644 1.Permutations and Combinations$keywords Permutation, Combination.md diff --git a/1.Permutations and Combinations$keywords Permutation, Combination.md b/1.Permutations and Combinations$keywords Permutation, Combination.md deleted file mode 100644 index 0b49736..0000000 --- a/1.Permutations and Combinations$keywords Permutation, Combination.md +++ /dev/null @@ -1,334 +0,0 @@ -##1.Permutations and Combinations$keywords [Permutation](#PermutationAnchor), [Combination](#CombinationAnchor) - -###*Permutation -一般来说有两种解题思路,一种是利用递归生成所有的Permutation,另一种是利用求上一个/下一个Permutation来求出所有的Permutation。该题有可分为有重复和无重复元素的情况。求上一个/下一个的方法适用于有重复和无重复的情况,不需要做适应化修改 -而递归方法在有重复元素的情况下需要修改为对当次递归相同的元素做跳过处理。 - -Ex1:[LeetCode:next Permutation](http://oj.leetcode.com/problems/next-permutation/) - -高效的方法求下一个Permutation。定义单调递增为最小的序列(如1,2,3,4,5),单调递减为最大的序列(如5,4,3,2,1),序列1,2,3,4,5的下一个Permutation为1,2,3,5,4,序列5,4,3,2,1的下一个Permutation为1,2,3,4,5。 - -可以这样理解该方法,想象当前数列形成一个开口向下的折线,折线的左半部分单调递增,折线的右半部分单调递减。对于右半单调递减部分(包含顶点),已经没有办法调换其中的数字使得整体数列变大,因为其本身已经是右半部分子序列的最大情形,因此通过交换左半递增部分和右半递减部分来实现,交换的两数为**折线顶点左侧的第一个数x**和**右半递减部分第一个大于x的数y**,这样保证了产生了比原来更大的序列(因为y>x)。为了完成目标,还需要对原右半递减部分进行升序排序,保证产生了恰比原来大的序列(选用了第一个大于x的y且右半部分经过排序成为右半部分的最小序列)。 - -这里可以用倒置右半部分代替排序,原因是y是第一个大于x的数,交换这两个数不会打破右半部分的单调递减特性。 -```cpp -class Solution { -public: - void nextPermutation(vector &num) { - for(int i = num.size()-1; i>=1; i--){//改变右起的第一个升序对可以使序列变大 - if(num[i]>num[i-1]){//num[i-1]和num[i]是第一个升序对,此时从i到size()-1是降序 - for(int j = num.size()-1; j>=i; j--){ - if(num[j]>num[i-1]){ - swap(num[j], num[i-1]); - reverse(num.begin()+i,num.end()); - return; - } - } - } - } - reverse(num.begin(),num.end());//说明是降序,直接反转为升序为最小的排列 - } -}; -``` -Ex2:[LeetCode:Permutation Sequence](http://oj.leetcode.com/problems/permutation-sequence/) - -此题要求寻找给定位数的Permutation的第k个序列,以单调递增序列(如1,2,3,4,5)作为第1个序列。 - -同样应用Ex1中的方法求解,c为长度为n的Permutation总数。为了减少迭代次数,可以看k与c/2的大小关系从两头求解,求上一个Permutation的方法与Ex1类似,详略。 - -**注意点1**:k不一定小于c,需要做mod运算 - -**注意点2**:使用stringstream可以快速将int转换为string -```cpp -class Solution { -public: - string getPermutation(int n, int k) { - string result, temp; - stringstream ss; - int c = 1; - bool isGenerated = false; - - for(int i = 1; i<=n; i++){ - c *= i; - } - k = k % c; - if(k == 0) k = c; - - for(int i = 1; i<=n; i++){ - if(k<=c/2){ - ss<>temp; - result += temp; - ss.clear(); - } - - if(k<=c/2){ - for(int i = 1 ; i < k; i++){//求下一个permutation - isGenerated = false; - for(int j = result.length()-1; j>=1 && !isGenerated; j--){ - if(result[j]>result[j-1]){ - for(int k = result.length()-1; k >= j && !isGenerated; k--){ - if(result[k]>result[j-1]){ - swap(result[k], result[j-1]); - reverse(&result[j],&result[result.length()]); - isGenerated = true; - } - } - } - } - } - }else{ - for(int i = 1 ; i < c-k+1; i++){//求上一个permutation - isGenerated = false; - for(int j = result.length()-1; j>=1 && !isGenerated; j--){ - if(result[j]= j && !isGenerated; k--){ - if(result[k] v; - string s = ""; - if(k>o[n]) - return s; - for(int i=1;i<=n;i++) - v.push_back(i); - while(n>0){ - int cnt = (k-1)/o[n-1]; - s+=v[cnt]+'0'; - v.erase(v.begin()+cnt); - k=k%o[n-1]; - if(k==0) - k=o[n-1]; - n--; - } - - return s; -} -``` - -Ex3:[LeetCode:Permutations](http://oj.leetcode.com/problems/permutations/) - -此题要求求出无重复数字的所有的排列,方法可以应用前述的求下一个排列的方法。此处使用递归的方法求解。 - -组合的递归求解方法,可以理解为在每一次递归过程内为当前位置选择一个数。使用一个Stack(此处使用Vector模拟,也即generated)记录已生成的排列,同时使用一个Vector记录剩余可选择的数。 -```cpp -class Solution { -public: - vector > result; - vector > permute(vector &num) { - if(num.size() == 0) return result; - vector temp; - genPermutation(temp, num); - return result; - } - - void genPermutation(vector generated, vector num){ - if(num.empty()){ - result.push_back(generated); - return; - } - generated.push_back(-1); - for(int i = 0; i <= num.size()-1; i++){ - generated.pop_back(); - generated.push_back(num[i]); - swap(num[0], num[i]); - genPermutation(generated, vector(num.begin()+1, num.end())); - } - return; - } -}; -``` -Ex4:[LeetCode:Permutations II](http://oj.leetcode.com/problems/permutations-ii/) - -与Ex3相比,本题输入可能为有重复的序列,使用求下一个序列的方法仍然可用,此处省略。 - -使用递归方法求解,基本思路与LeetCode:Permutations的递归解法类似,但在同一次递归过程中不能选择大小相等的数,否则会生成重复序列。此处通过始终保持待选数字Vector有序,判断当前数字是否与上一个数字相等来去重。 - -**注意点1**:因为交换后传参,每次进入递归时都要对待选数字Vector排序 - -**注意点2**:选择每个数字后需要再次交换保证待选数字Vector有序 - -```cpp -class Solution { -public: - //recursive - vector > result; - vector > permuteUnique(vector &num) { - if(num.size() == 0) return result; - vector generated; - sort(num.begin(), num.end()); - genPermutation(generated, num); - return result; - } - - void genPermutation(vector generated, vector num){ - if(num.size() == 0){ - result.push_back(generated); - return; - } - sort(num.begin(), num.end()); - generated.push_back(-1); - for(int i = 0; i <= num.size()-1; i++){ - if((i == 0) || num[i] != num[i-1]){ - generated.pop_back(); - generated.push_back(num[i]); - swap(num[0], num[i]); - genPermutation(generated, vector(num.begin()+1, num.end())); - swap(num[0], num[i]); - } - } - } -}; -``` - -###*Combination -对于Combination通常的解法是递归,与Permutation不同的地方在于每个递归过程只需考虑是否选当前数字,这是Combination由位置无关特性决定的。 - -Ex5:[LeetCode:Combinations](http://oj.leetcode.com/problems/combinations/) - -该题要求求出1...n的长度为k的组合结果集合,很容易想到递归,对于每个数都有选与不选两种选择,使用一个Stack(此处用Vecotr模拟)记录已选组合。 -```cpp -class Solution { -public: - vector > result; - vector > combine(int n, int k) { - // IMPORTANT: Please reset any member data you declared, as - // the same Solution instance will be reused for each test case. - if(n <= 0 || k <= 0) return result; - vector temp; - temp.clear(); - k = k % n; - if(k == 0) k = n; - genCombination(temp,1, n, k); - return result; - } - - void genCombination(vector& temp, int start, int end, int k){ - //比较正统的办法,每次递归都有两个选择:选或不选 - if(k == 0){ - result.push_back(temp); - return; - } - if(start>end) return; - //if(end-start+1& temp, int start, int end, int k){ - //一个较为取巧的办法,利用结果的单调性,给下一次递归传i+1,循环的过程实际上替代了不选某(或某些)数的递归过程 - if(k == 0){ - result.push_back(temp); - return; - } - //if(end-start+1 result; - vector letterCombinations(string digits) { - string temp; - recursion(digits, temp, 0); - return result; - } - - void recursion(string &digits, string temp, int index){ - if(index == digits.size()){ - result.push_back(temp); - } - vector charV = toChar(digits[index]-'0'); - for(vector::iterator itr = charV.begin(); itr != charV.end(); itr++){ - recursion(digits, temp+(*itr), index+1); - } - } - - vector toChar(int i){ - vector result; - switch(i){ - case 2: - result.push_back('a'); - result.push_back('b'); - result.push_back('c'); - break; - case 3: - result.push_back('d'); - result.push_back('e'); - result.push_back('f'); - break; - case 4: - result.push_back('g'); - result.push_back('h'); - result.push_back('i'); - break; - case 5: - result.push_back('j'); - result.push_back('k'); - result.push_back('l'); - break; - case 6: - result.push_back('m'); - result.push_back('n'); - result.push_back('o'); - break; - case 7: - result.push_back('p'); - result.push_back('q'); - result.push_back('r'); - result.push_back('s'); - break; - case 8: - result.push_back('t'); - result.push_back('u'); - result.push_back('v'); - break; - case 9: - result.push_back('w'); - result.push_back('x'); - result.push_back('y'); - result.push_back('z'); - break; - } - return result; - } -}; -``` diff --git a/Array & String.md b/Array & String.md index b8881e5..ce1f0dd 100644 --- a/Array & String.md +++ b/Array & String.md @@ -6,8 +6,9 @@ Index: -[Find Min K](#Anchor3) -[Find Number occurs half times](#Anchor4) -[Leetcode:Median of Two Sorted Arrays](#Anchor5) --[Leetcode:Longest Substring Without Repeating Characters](#Anchor6) --[Leetcode:Substring with Concatenation of All Words](#Anchor7) +-[Leetcode:Longest Substring Without Repeating Characters](#Anchor6) +-[Leetcode:Substring with Concatenation of All Words](#Anchor7) +-[LeetCode:Next Permutation](#Anchor8) ------- @@ -368,7 +369,7 @@ public: int n = s.size(); if(n == 0) return ret; int fast = 0, slow = 0; - unordered_set charDict; + unordered_set< char > charDict; while(fast <= n-1){ if(charDict.find(s[fast]) != charDict.end()){ int len = fast - slow; @@ -387,7 +388,9 @@ public: ``` ------- + + -**[Leetcode:Substring with Concatenation of All Words](http://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/)**([Back to Index](#AnchorIndex)) 一个比较直观的解法(不一定最优)。维护一个< 单词,个数 >map,假设L中单词长度为wordLen,每次从S中截取L.size()*wordLen的子串,判断该子串是否能完全消耗map中的单词,如果可以,则该起始位置为有效解;如果不能,则将起始位置向后推进wordLen个位置。 @@ -435,4 +438,70 @@ public: return ret; } }; +``` + +------- + +-**[LeetCode:Next Permutation](http://oj.leetcode.com/problems/next-permutation/)**([Back to Index](#AnchorIndex)) + +高效的方法求下一个Permutation。定义单调递增为最小的序列(如1,2,3,4,5),单调递减为最大的序列(如5,4,3,2,1),序列1,2,3,4,5的下一个Permutation为1,2,3,5,4,序列5,4,3,2,1的下一个Permutation为1,2,3,4,5。 + +可以这样理解该方法,想象当前数列形成一个开口向下的折线,折线的左半部分单调递增,折线的右半部分单调递减。对于右半单调递减部分(包含顶点),已经没有办法调换其中的数字使得整体数列变大,因为其本身已经是右半部分子序列的最大情形,因此通过交换左半递增部分和右半递减部分来实现,交换的两数为**折线顶点左侧的第一个数x**和**右半递减部分第一个大于x的数y**,这样保证了产生了比原来更大的序列(因为y > x)。为了完成目标,还需要对原右半递减部分进行升序排序,保证产生了恰比原来大的序列(选用了第一个大于x的y且右半部分经过排序成为右半部分的最小序列)。 + +这里可以用倒置右半部分代替排序,原因是y是第一个大于x的数,交换这两个数不会打破右半部分的单调递减特性。 + +注意,该方法适用于具有重复元素的数组生成下一个排列。 +```cpp +class Solution { +public: + void nextPermutation(vector &num) { + for(int i = num.size()-1; i>=1; i--){//改变右起的第一个升序对可以使序列变大 + if(num[i]>num[i-1]){//num[i-1]和num[i]是右起第一个升序对,此时下标从i到size()-1的元素是降序 + for(int j = num.size()-1; j>=i; j--){ + if(num[j]>num[i-1]){ + swap(num[j], num[i-1]); + reverse(num.begin()+i,num.end()); + return; + } + } + } + } + reverse(num.begin(),num.end());//说明是降序,直接反转为升序为最小的排列 + } +}; +``` + +------- + +-**[LeetCode:Permutation Sequence](http://oj.leetcode.com/problems/permutation-sequence/)**([Back to Index](#AnchorIndex)) + +此题要求寻找给定位数的Permutation的第k个序列,以单调递增序列(如1,2,3,4,5)作为第1个序列。可以应用[Next Permutation](#Anchor8)方法,但效率太低。 + +此处使用另外一种方法求解。*TODO*:算法说明。 + +注意,给定的k可能超过n!。 + +```cpp +string getPermutation(int n, int k) { + int o[n+1]; + o[0]=1; + for(int i=1;i<=n;i++) + o[i]=o[i-1]*i; + vector v; + string s = ""; + if(k>o[n]) + return s; + for(int i=1;i<=n;i++) + v.push_back(i); + while(n>0){ + int cnt = (k-1)/o[n-1]; + s+=v[cnt]+'0'; + v.erase(v.begin()+cnt); + k=k%o[n-1]; + if(k==0) + k=o[n-1]; + n--; + } + return s; +} ``` \ No newline at end of file diff --git a/README.md b/README.md index 5cfeabb..8989fcc 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,13 @@ Chapters Core contributors ------------ -[@sc703bupt](https://github.com/sc703bupt) +[@sc703bupt](https://github.com/sc703bupt) [@popolou](https://github.com/popolou) + +Contributors +------------ +[@jasonZhouChao](https://github.com/jasonZhouChao) + Contact us ------------ 欢迎提出意见和建议到sc1_1@163.com. From 6e0594cd39cf7abca1106c602f034e817501e35d Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Wed, 29 Oct 2014 14:16:58 +0800 Subject: [PATCH 301/327] merging --- 8.Rewrite STL$keywords rewrite.md | 472 ---------------------------- Array & String.md | 134 ++++++++ Basic Algorithm & Data Structure.md | 69 ++++ Functions in string.h.md | 172 ++++++++++ Others.md | 75 ++++- README.md | 3 +- 6 files changed, 451 insertions(+), 474 deletions(-) delete mode 100644 8.Rewrite STL$keywords rewrite.md create mode 100644 Functions in string.h.md diff --git a/8.Rewrite STL$keywords rewrite.md b/8.Rewrite STL$keywords rewrite.md deleted file mode 100644 index 8cd87d7..0000000 --- a/8.Rewrite STL$keywords rewrite.md +++ /dev/null @@ -1,472 +0,0 @@ -##8.Rewrite STL$keywords Rewrite -###*Rewrite STL -Ex1:[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/) - -从前向后比对,实现 - -```cpp -class Solution { -public: - char *strStr(char *haystack, char *needle) { - int len1 = strlen(haystack); - int len2 = strlen(needle); - if (len1 < len2) - return NULL; - if (len2 == 0) - return haystack; - char* p2 = haystack; - for (int i = 0; i < len1 - len2 + 1; i++) { - char* p1 = needle; - char* p_old = (char*) p2; - while (*p1 && *p2) { - if (*p1 == *p2) { - p1++; - p2++; - } else - break; - } - if (!*p1) - return p_old; - p2 = p_old + 1; - } - return NULL; - } -}; -``` - -Ex2:[Leetcode:String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) -主要判断溢出问题 -```cpp -class Solution { -public: - - int atoi(const char *str) { - int i = 0; - int len = strlen(str); - bool positive = true; - while (str[i] == ' ' && i < len) - i++; - if (str[i] == '+') - i++; - else if (str[i] == '-') { - positive = false; - i++; - } - long long sum = 0; - for (; i < len; i++) { - if (str[i] < '0' || str[i] > '9') - break; - sum = sum * 10 + str[i] - '0'; - } - sum = positive == true ? sum : -1 * sum; - int min = 0x80000000; - int max = 0x7fffffff; - if (sum < min) - return 0x80000000; - else if (sum > max) - return 0x7fffffff; - return (int) sum; - } -}; -``` - -Ex3:[Leetcode:Add Binary](http://oj.leetcode.com/problems/add-binary/) -记录标记位 -```cpp -//add Binary - -class Solution { -public: - - string addBinary(string a, string b) { - // Start typing your C/C++ solution below - // DO NOT write int main() function - string c; - int flag = 0; - int lena = a.size(); - int lenb = b.size(); - int len = abs(lena - lenb); - string append(len, '0'); - if (lena > lenb) { - b = append + b; - c.resize(lena, '0'); - } else { - a = append + a; - c.resize(lenb, '0'); - } - for (int j = c.size() - 1; j >= 0; j--) { - int current = (a[j] - '0') ^(b[j] - '0') ^flag; - if ((a[j] - '0') +(b[j] - '0') + flag > 1) - flag = 1; - else - flag = 0; - c[j] = current + '0'; - } - if (flag == 1) - c = '1' + c; - - return c; - - } -}; -``` -Ex4:[Leetcode:Valid Number](oj.leetcode.com/problems/valid-number/) -复杂的判断条件 -```cpp -class Solution { -public: - - bool isNumber(const char *s) { - if (s == NULL || s[0] == '\0') return false; - bool cansign = true; - bool cane = false; - bool havee = false; - bool candot = true; - bool onlyspace = false; - bool havenum = false; - bool numbegin = false; - while (*s != '\0') { - char c = *(s++); - if (c == ' ') { - if (numbegin) - onlyspace = true; - continue; //skip space - } else if (onlyspace) { - return false; - } - if (c == '+' || c == '-') { - if (!cansign) return false; - cansign = false; - numbegin = true; - continue; - } - if (c == 'e') { - if (!cane) return false; - cane = false; - havenum = false; - numbegin = true; - cansign = true; - havee = true; - candot = false; - continue; - } - if (c == '.') { - if (!candot) return false; - candot = false; - numbegin = true; - cansign = false; - continue; - } - if (c >= '0' && c <= '9') { - havenum = true; - numbegin = true; - cansign = false; - if (!havee) cane = true; - } else { - return false; - } - } - return havenum; - } -}; -``` -Ex5:[Leetcode:Pow(x, n)](http://oj.leetcode.com/problems/powx-n/) -二分法 -```cpp -class Solution { -public: - double pow(double x, int n) { - // Start typing your C/C++ solution below - // DO NOT write int main() function - if(n == 0) return 1; - else if(n > 0) - { - double half = pow(x, n/2); - if(n%2 == 0) return half*half; - else return half*half*x; - } - else - { - n = -n; - double half = pow(x, n/2); - if(n%2 == 0) return 1.0/(half*half); - else return 1.0/(half*half*x); - } - } -}; -``` - -Ex6:[Leetcode:Sqrt(x)](http://oj.leetcode.com/problems/sqrtx/) -二分法 -```cpp -class Solution { -public: - - int sqrt(int x) { - int left = 1, right = x / 2; - int mid; - int last_mid; // 记录最近一次mid - if (x < 2) return x; - while (left <= right) { - mid = left + (right - left) / 2; - if (x / mid > mid) { // 不要用x > mid * mid,会溢出 - left = mid + 1; - last_mid = mid; - } else if (x / mid < mid) { - right = mid - 1; - } else { - return mid; - } - } - return last_mid; - } -}; -``` -Ex7:[Leetcode:Multiply Strings](http://oj.leetcode.com/problems/multiply-strings/) -```cpp -class Solution { -public: - string multiply(string num1, string num2) { - int len1 = num1.length(); - int len2 = num2.length(); - vector res(len1+len2); - vector n1; - vector n2; - for(int i=num1.length()-1;i>=0;--i) - n1.push_back(num1[i]-'0'); - for(int i=num2.length()-1;i>=0;--i) - n2.push_back(num2[i]-'0'); - for(int i=0;i=0) - --i; - if(i<0) - return "0"; - while(i>=0){ - ret.push_back('0'+res[i]-0); - --i; - } - return ret; - } -}; -``` -Ex8:strcpy -原型声明:char *strcpy(char* dest, const char *src); -头文件:#include -功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间 -说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,这些都需要调用者来保障。 -返回指向dest的指针。 - -一个较好的实现: -```cpp -char* strcpy(char* strDest, const char* strSrc){ - if(strDest == strSrc){ - return strDest; - } - assert((strDest != NULL) && (strSrc != NULL)); - char* address = strDest; - while((*strDest++ = *strSrc++)!='\0'); - return address; -} - -``` - -Ex9:memcpy -原型声明:void *memcpy(void *dest, const void *src, size_t n); -头文件:C语言中使用#include ; - C++中使用#include 和#include 都可以 -功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中 -说明: -1.source和destin所指的内存区域可以重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针. -2.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。 -注意:source和destin都不一定是数组,任意的可读写的空间均可。 - -一个较好的实现: -```cpp -void * memcpy(void * destaddr,void const * srcaddr, size_t len){ - char* dest = destaddr; - const char * src = srcaddr; - while(len-- > 0){ - *dest++ = *src++; - } - return destaddr; -} - -``` - -Ex10:memset -原型声明:void *memset(void *s, int ch, size_t n); -头文件: or memset wmemset -功能:将s中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s 。 -说明:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。 - -一个较好的实现: -```cpp -void * memset(void *str, int c, size_t count){ - assert(str != NULL); - void *s = str; - while(count--){ - *(char*)s = (char) c; - s = (char*)s + 1; - } - return str; -} - -``` -错误使用示例: -1. -```cpp -int f(int a[]){ - memset(a,0,sizeof(a)); - } -``` -a会退化为指针,导致不能按照预想的方式初始化数组。 - -2. -```cpp -int f(){ - int a[5]; - memset(a,1,20); - for(int i = 0; i < 5; i++){ - cout << a[i] << " "; - } - } -``` -由于memset是按照字节拷贝,因此a中的每个元素都会被初始化为0x01010101而不是1。 -3. -```cpp -int f(){ - char* s = "12345"; - memset(s,'1',5); -} -``` -运行时错误,因为s指向的是常量区(不可写内存区域),对该区域的写操作会导致程序崩溃。换成char * s = new char[5];或者char s[] = "12345";则没有问题,前者是在堆上的可读写区域,后者是在栈上的可读写区域。 - -Ex11:strstr -原型声明:char *strstr(const char *str1, const char *str2); -头文件: -功能:该函数返回str2第一次在str1中的位置,如果没有找到,返回NULL -说明:注意两个参数均是const - -一个较好的实现: -```cpp -char* strstr(const char* strSrc, const char* str){ - assert(strSrc != NULL && str != NULL); - const char* s = strSrc; - const char* t = str; - for(; *strSrc != '\0'; strSrc++){ - for(s = strSrc, t = str; *t != '\0' && *s == *t; s++, t++){} - if(*t == '\0') return (char*)strSrc; - } - return NULL; -} - -``` - -Ex12:strcmp -原型声明:unsigned int strlen(const char *str); -头文件: -功能:返回以'\0'结尾的字符串长度,但不包括'\0' -说明:注意strlen只能接受char*的参数,不能与sizeof混淆 - -一个较好的实现: -```cpp -unsigned int strlen(const char* str){ - assert(str != NULL); - const char * eos = str; - while(*eos++); - return (unsigned int)(eos-str-1); -} - -``` - -Ex13:strcat -原型声明:char *strcat(char *dest, const char *src); -头文件: -功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。 -说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针。 - -一个较好的实现: -```cpp -char* strcat(char* dest, const char* src){ - assert((dest != NULL) && (src != NULL)); - char * ret = dest; - while(*dest){ - dest++; - } - while(*dest++ = *src++){} - return ret; -} - -``` - -Ex14:QuickSort in Linklist -主要思路是在做partition的时候将链表分为三个部分,做递归之前注意将每一段的尾部置空,合并时注意判断边界条件。 -```cpp -#include - -using namespace std; - -class ListNode{ -public: - int val; - ListNode * next; - ListNode(int _val):val(_val),next(NULL){} -}; - -ListNode * quickSort(ListNode * head){ - if(head == NULL || head->next == NULL){ - return head; - } - ListNode dummyFront(-1), dummyMid(-1), dummyBack(-1); - ListNode * frontTail = NULL, * midTail = NULL, * backTail = NULL; - int num = head->val; - for(ListNode * itr = head; itr != NULL; itr = itr->next){ - if(itr->val == num){ - if(midTail == NULL){ - dummyMid.next = itr; - midTail = itr; - }else{ - midTail->next = itr; - midTail = midTail->next; - } - }else if(itr->val < num){ - if(frontTail == NULL){ - dummyFront.next = itr; - frontTail = itr; - }else{ - frontTail->next = itr; - frontTail = frontTail->next; - } - }else{ - if(backTail == NULL){ - dummyBack.next = itr; - backTail = itr; - }else{ - backTail->next = itr; - backTail = backTail->next; - } - } - } - if(frontTail != NULL) frontTail->next = NULL; - if(midTail != NULL) midTail->next = NULL; - if(backTail != NULL) backTail->next = NULL; - ListNode * frontRet = quickSort(dummyFront.next); - ListNode * backRet = quickSort(dummyBack.next); - ListNode * ret = frontRet == NULL ?dummyMid.next:frontRet; - if(frontRet != NULL){ - ListNode * itr = NULL; - for(itr = frontRet; itr->next != NULL; itr = itr->next){} - itr->next = dummyMid.next; - } - midTail->next = backRet; - return ret; -} -``` diff --git a/Array & String.md b/Array & String.md index ce1f0dd..42c3298 100644 --- a/Array & String.md +++ b/Array & String.md @@ -9,6 +9,10 @@ Index: -[Leetcode:Longest Substring Without Repeating Characters](#Anchor6) -[Leetcode:Substring with Concatenation of All Words](#Anchor7) -[LeetCode:Next Permutation](#Anchor8) +-[LeetCode:Permutation Sequence](#Anchor9) +-[Leetcode:Multiply Strings](#Anchor10) +-[Leetcode:Implement strStr()](#Anchor11) +-[Leetcode:String to Integer (atoi)](#Anchor12) ------- @@ -504,4 +508,134 @@ string getPermutation(int n, int k) { } return s; } +``` + +------- + +-**[Leetcode:Multiply Strings](http://oj.leetcode.com/problems/multiply-strings/)**([Back to Index](#AnchorIndex)) + +限定此题的输入为两个正整数字符串,要求这两个正整数的乘积。思路比较清晰: + + a) 对num1逆序 + b) 对num2逆序 + c) res[i+j] += num1[i] * num2[j]; + d) res[i+j+1] += res[i+j] / 10; + e) res[i+j] = res[i+j] % 10; + +注意最后检查结果是否全为0,并去除结果的前导0。 + +```cpp +class Solution { +public: + string multiply(string num1, string num2) { + int len1 = num1.length(); + int len2 = num2.length(); + vector res(len1+len2); + vector n1; + vector n2; + for(int i=num1.length()-1;i>=0;--i) + n1.push_back(num1[i]-'0'); + for(int i=num2.length()-1;i>=0;--i) + n2.push_back(num2[i]-'0'); + for(int i=0;i=0) + --i; + if(i<0) + return "0"; + while(i>=0){ + ret.push_back('0'+res[i]-0); + --i; + } + return ret; + } +}; +``` + +------- + +-**[Leetcode:Implement strStr()](oj.leetcode.com/problems/implement-strstr/)**([Back to Index](#AnchorIndex)) + +haystack为主串,needle为匹配串。思路比较简单:每次选取主串中的一个字符作为主串的起始匹配位置,选取子串的头作为另一个起始匹配位置,匹配跳出条件: + + * 对应位置字符不同 + * 两个字符串的其中一个或两个均到达'\0'位置 + +可以这些跳出情况,只需要判断跳出时needle是否已经到达'\0'位置即可,如果到达,则说明找到该子串,返回该子串在主串中的头字符位置即可。 + +```cpp +class Solution { +public: + char *strStr(char *haystack, char *needle) { + int len1 = strlen(haystack); + int len2 = strlen(needle); + if (len1 < len2) + return NULL; + if (len2 == 0) + return haystack; + char* p2 = haystack; + for (int i = 0; i < len1 - len2 + 1; i++) { + char* p1 = needle; + char* p_old = (char*) p2; + while (*p1 && *p2) { + if (*p1 == *p2) { + p1++; + p2++; + } else + break; + } + if (!*p1) + return p_old; + p2 = p_old + 1; + } + return NULL; + } +}; +``` + +------- + +-**[Leetcode:String to Integer (atoi)](oj.leetcode.com/problems/string-to-integer-atoi/) **([Back to Index](#AnchorIndex)) + +注意判断先导空格,符号和溢出情况。 + +```cpp +class Solution { +public: + + int atoi(const char *str) { + int i = 0; + int len = strlen(str); + bool positive = true; + while (str[i] == ' ' && i < len) + i++; + if (str[i] == '+') + i++; + else if (str[i] == '-') { + positive = false; + i++; + } + long long sum = 0; + for (; i < len; i++) { + if (str[i] < '0' || str[i] > '9') + break; + sum = sum * 10 + str[i] - '0'; + } + sum = positive == true ? sum : -1 * sum; + int min = 0x80000000; + int max = 0x7fffffff; + if (sum < min) + return 0x80000000; + else if (sum > max) + return 0x7fffffff; + return (int) sum; + } +}; ``` \ No newline at end of file diff --git a/Basic Algorithm & Data Structure.md b/Basic Algorithm & Data Structure.md index 144098c..ccd12a8 100644 --- a/Basic Algorithm & Data Structure.md +++ b/Basic Algorithm & Data Structure.md @@ -5,6 +5,7 @@ Index: -[Union Find Sets](#Anchor2) -[Nonrecursive Tree Traversal](#Anchor3) -[KMP](#Anchor4) +-[QuickSort in Linklist](#Anchor5) ------- @@ -203,4 +204,72 @@ int main() { return 0; } +``` + +------- + +-**QuickSort in Linklist**([Back to Index](#AnchorIndex)) + +主要思路是在做partition的时候将链表分为三个部分,做递归之前注意将每一段的尾部置空,合并时注意判断边界条件。在做链表拆分的时候使用了虚拟节点(dummy node)作为链表头,可以大大简化程序逻辑,推荐使用。 + +```cpp +#include + +using namespace std; + +class ListNode{ +public: + int val; + ListNode * next; + ListNode(int _val):val(_val),next(NULL){} +}; + +ListNode * quickSort(ListNode * head){ + if(head == NULL || head->next == NULL){ + return head; + } + ListNode dummyFront(-1), dummyMid(-1), dummyBack(-1); + ListNode * frontTail = NULL, * midTail = NULL, * backTail = NULL; + int num = head->val; + for(ListNode * itr = head; itr != NULL; itr = itr->next){ + if(itr->val == num){ + if(midTail == NULL){ + dummyMid.next = itr; + midTail = itr; + }else{ + midTail->next = itr; + midTail = midTail->next; + } + }else if(itr->val < num){ + if(frontTail == NULL){ + dummyFront.next = itr; + frontTail = itr; + }else{ + frontTail->next = itr; + frontTail = frontTail->next; + } + }else{ + if(backTail == NULL){ + dummyBack.next = itr; + backTail = itr; + }else{ + backTail->next = itr; + backTail = backTail->next; + } + } + } + if(frontTail != NULL) frontTail->next = NULL; + if(midTail != NULL) midTail->next = NULL; + if(backTail != NULL) backTail->next = NULL; + ListNode * frontRet = quickSort(dummyFront.next); + ListNode * backRet = quickSort(dummyBack.next); + ListNode * ret = frontRet == NULL ?dummyMid.next:frontRet; + if(frontRet != NULL){ + ListNode * itr = NULL; + for(itr = frontRet; itr->next != NULL; itr = itr->next){} + itr->next = dummyMid.next; + } + midTail->next = backRet; + return ret; +} ``` \ No newline at end of file diff --git a/Functions in string.h.md b/Functions in string.h.md new file mode 100644 index 0000000..84030eb --- /dev/null +++ b/Functions in string.h.md @@ -0,0 +1,172 @@ +##Functions In string.h + +Index: +-[strcpy](#Anchor1) +-[memcpy](#Anchor2) +-[memset](#Anchor3) +-[strstr](#Anchor4) +-[strlen](#Anchor5) +-[strcat](#Anchor6) + +------- + +-**[strcpy]**([Back to Index](#AnchorIndex)) + +原型声明:char * strcpy(char * dest, const char * src); +头文件:#include +功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间 +说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,这些都需要调用者来保障。 +返回指向dest的指针。 + +实现: +```cpp +char* strcpy(char* strDest, const char* strSrc){ + if(strDest == strSrc){ + return strDest; + } + assert((strDest != NULL) && (strSrc != NULL)); + char* address = strDest; + while((*strDest++ = *strSrc++)!='\0'); + return address; +} +``` + +------- + +-**[memcpy]**([Back to Index](#AnchorIndex)) + +原型声明:void *memcpy(void *dest, const void *src, size_t n); +头文件:C语言中使用#include ; + C++中使用#include 和#include 都可以 +功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中 +说明: +1.source和destin所指的内存区域可以重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针. +2.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。 +注意:source和destin都不一定是数组,任意的可读写的空间均可。 + +实现: +```cpp +void * memcpy(void * destaddr,void const * srcaddr, size_t len){ + char* dest = destaddr; + const char * src = srcaddr; + while(len-- > 0){ + *dest++ = *src++; + } + return destaddr; +} +``` + +------- + +-**[memset]**([Back to Index](#AnchorIndex)) + +原型声明:void *memset(void *s, int ch, size_t n); +头文件: or memset wmemset +功能:将s中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s 。 +说明:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。 + +实现: +```cpp +void * memset(void *str, int c, size_t count){ + assert(str != NULL); + void *s = str; + while(count--){ + *(char*)s = (char) c; + s = (char*)s + 1; + } + return str; +} +``` +错误使用示例: +1. +```cpp +int f(int a[]){ + memset(a,0,sizeof(a)); + } +``` +a会退化为指针,导致不能按照预想的方式初始化数组。 + +2. +```cpp +int f(){ + int a[5]; + memset(a,1,20); + for(int i = 0; i < 5; i++){ + cout << a[i] << " "; + } + } +``` +由于memset是按照字节拷贝,因此a中的每个元素都会被初始化为0x01010101而不是1。 +3. +```cpp +int f(){ + char* s = "12345"; + memset(s,'1',5); +} +``` +运行时错误,因为s指向的是常量区(不可写内存区域),对该区域的写操作会导致程序崩溃。换成char * s = new char[5];或者char s[] = "12345";则没有问题,前者是在堆上的可读写区域,后者是在栈上的可读写区域。 + +------- + +-**[strstr]**([Back to Index](#AnchorIndex)) + +原型声明:char *strstr(const char *str1, const char *str2); +头文件: +功能:该函数返回str2第一次在str1中的位置,如果没有找到,返回NULL +说明:注意两个参数均是const + +实现: +```cpp +char* strstr(const char* strSrc, const char* str){ + assert(strSrc != NULL && str != NULL); + const char* s = strSrc; + const char* t = str; + for(; *strSrc != '\0'; strSrc++){ + for(s = strSrc, t = str; *t != '\0' && *s == *t; s++, t++){} + if(*t == '\0') return (char*)strSrc; + } + return NULL; +} +``` + +------- + +-**[strlen]**([Back to Index](#AnchorIndex)) + +原型声明:unsigned int strlen(const char *str); +头文件: +功能:返回以'\0'结尾的字符串长度,但不包括'\0' +说明:注意strlen只能接受char*的参数,不能与sizeof混淆 + +实现: +```cpp +unsigned int strlen(const char* str){ + assert(str != NULL); + const char * eos = str; + while(*eos++); + return (unsigned int)(eos-str-1); +} +``` + +------- + +-**[strcat]**([Back to Index](#AnchorIndex)) + +原型声明:char *strcat(char *dest, const char *src); +头文件: +功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。 +说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针。 + +实现: +```cpp +char* strcat(char* dest, const char* src){ + assert((dest != NULL) && (src != NULL)); + char * ret = dest; + while(*dest){ + dest++; + } + while(*dest++ = *src++){} + return ret; +} + +``` \ No newline at end of file diff --git a/Others.md b/Others.md index 0d7c004..eb10c26 100644 --- a/Others.md +++ b/Others.md @@ -3,6 +3,9 @@ Index: -[Find the number(not exceeding M) only formed by 0 and 1](#Anchor1) -[Leetcode:Gray Code](#Anchor2) +-[Leetcode:Pow(x, n)](#Anchor3) +-[Leetcode:Sqrt(x)](#Anchor4) +-[*TODO*::Leetcode:Valid Number](#Anchor5) ------- @@ -69,6 +72,7 @@ public class MyOwn { } ``` +------- -**[Leetcode:Gray Code](http://oj.leetcode.com/problems/gray-code/)**([Back to Index](#AnchorIndex)) 一个普通解法: @@ -104,4 +108,73 @@ public: return vec; } }; -``` \ No newline at end of file +``` + +------- + +-**[Leetcode:Pow(x, n)](http://oj.leetcode.com/problems/powx-n/)**([Back to Index](#AnchorIndex)) + +求解x的n次方,可以考虑如下分类法 + + * 如果n = 0,则返回1 + * 如果n > 0,则先求解x的n/2次方结果,再根据奇偶性决定是否额外乘以x + * 如果n < 0,则对n取绝对值,即求解x的-(n/2)次方的结果,在根据奇偶性决定是否额外乘以x,注意此时返回值需要取倒数 + +```cpp +class Solution { +public: + double pow(double x, int n) { + // Start typing your C/C++ solution below + // DO NOT write int main() function + if(n == 0) return 1; + else if(n > 0) + { + double half = pow(x, n/2); + if(n%2 == 0) return half*half; + else return half*half*x; + } + else + { + n = -n; + double half = pow(x, n/2); + if(n%2 == 0) return 1.0/(half*half); + else return 1.0/(half*half*x); + } + } +}; +``` + +------- + +-**[Leetcode:Sqrt(x)](http://oj.leetcode.com/problems/sqrtx/)**([Back to Index](#AnchorIndex)) + +二分法。 + +```cpp +class Solution { +public: + + int sqrt(int x) { + int left = 1, right = x / 2; + int mid; + int last_mid; // 记录最近一次mid + if (x < 2) return x; + while (left <= right) { + mid = left + (right - left) / 2; + if (x / mid > mid) { // 不要用x > mid * mid,会溢出 + left = mid + 1; + last_mid = mid; + } else if (x / mid < mid) { + right = mid - 1; + } else { + return mid; + } + } + return last_mid; + } +}; +``` + +------- + +-**[Leetcode:Valid Number](oj.leetcode.com/problems/valid-number/)**([Back to Index](#AnchorIndex)) diff --git a/README.md b/README.md index 8989fcc..58b9921 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Chapters 1. [Basic Java Concepts](Basic Java Concepts.md) 2. [NIO](NIO.md) 3. [Big Data Processing](Big Data Processing.md) +4. [Functions In string.h](Functions in string.h.md) Core contributors ------------ @@ -39,6 +40,6 @@ Contributors Contact us ------------ -欢迎提出意见和建议到sc1_1@163.com. +欢迎提出意见和建议到 sc1_1@163.com. Any advice is appreciated, please send email to sc1_1@163.com. From bd13a4c72ae6bc7ffda8e91cf4b1bb868bf1e339 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Wed, 29 Oct 2014 15:16:41 +0800 Subject: [PATCH 302/327] merging --- 7.Area Computation$keyword stack.md | 230 ---------------------------- Dynamic Programming.md | 46 +++++- Greedy Strategy.md | 31 ++++ Stack.md | 130 +++++++++++++++- 4 files changed, 204 insertions(+), 233 deletions(-) delete mode 100644 7.Area Computation$keyword stack.md diff --git a/7.Area Computation$keyword stack.md b/7.Area Computation$keyword stack.md deleted file mode 100644 index 742d819..0000000 --- a/7.Area Computation$keyword stack.md +++ /dev/null @@ -1,230 +0,0 @@ -##7.Area Computation$keywords stack -###*Area Computation -本章会介绍几个计算给定一维/二维矩阵计算面积问题,类似的问题在[3.Sum$keywords Vector Sum, Tree Sum, Other Sum](3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md)的Other Sum小节也有提到,注意到第三章的问题特点 -1、数值可能为负,也即可能出现部分和为负的情况,此时可以很容易舍弃掉这个部分和,因其对后面的部分和没有贡献; -2、矩阵中的元素参与运算时并未受到临近元素的条件约束。 -本章提到的问题元素受临近元素的约束,适合用贪心/动态规划求解。开始了。 - -Ex1:[LeetCode:Container With Most Water](http://oj.leetcode.com/problems/container-with-most-water/) - -题意可理解为:给定一个数组,从中选出两个数字,从而使得以两个数字下标之差为宽,以两个数字较小者为高的矩形面积最大。使用两指针贪心法,总是移动数字较小的指针,贪心策略如下: -* 矩形面积受制于两下标之差,但这个差在两指针靠拢过程中总是缩小的,只能考虑高 -* 高是由较小者决定的,如果移动数字较大的,只能使面积变小(因为宽也变小了),而移动较小的则有可能变大 - -```cpp -class Solution { -public: - int maxArea(vector &height) { - if(height.size() == 0 || height.size() == 1) return 0; - int max = 0, S; - int low = 0, high = height.size()-1; - while(lowmax) max = S; - } - return max; - } -}; -``` - -Ex2:[LeetCode:Trapping Rain Water](http://oj.leetcode.com/problems/trapping-rain-water/) - -这道题如果从两指针的角度来看会变得非常复杂,要考虑每个区间内的柱高情况。换一个角度,只考虑每个柱子上方的容水量C[i] -* `C[i] = Min{LeftHighest[i],RightHighest[i]} - A[i]` - -其中,LeftHighest[i]是柱子i左侧的最高柱高度(不包括自身),RightHighest[i]是柱子i右侧的最高柱高度(不包括自身),A[i]是柱子i的高度。LeftHighest和RightHighest可以用dp求解,最后对C[i]求和即可得到结果。 - -```cpp -class Solution { -public: - int trap(int A[], int n) { - if(n<=2) return 0; - int units = 0; - vector leftHighest; - leftHighest.resize(n); - leftHighest[0] = 0; - for(int i = 1; i<=n-1; i++){ - if(A[i-1] < leftHighest[i-1]){ - leftHighest[i] = leftHighest[i-1]; - }else{ - leftHighest[i] = A[i-1]; - } - } - - int rightHighest = 0, tempUnit = 0; - for(int j = n-2; j>=1; j--){ - if(A[j+1]>rightHighest){ - rightHighest = A[j+1]; - } - tempUnit = min(leftHighest[j],rightHighest)-A[j]; - if(tempUnit <= 0) continue; - units += tempUnit; - } - return units; - } -}; -``` - -Ex3:[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/largest-rectangle-in-histogram/) - -此题如果用暴力求解同样十分繁琐,以下为O(n)解法,注意到 -* 以小矩形A[i]为高的矩形在整个直方图取到的最大面积取决于A[i]右侧的第一个比A[i]小的小矩形A[j]与A[i]形成的宽度 -* 如果小矩形A[i]左侧没有比A[i]小的小矩形,则宽度为0到A[j] -* 如果小矩形A[i]右侧没有比A[i]小的小矩形,且左侧也没有(即全局最小),则宽度为直方图的宽度 - -这里非常巧妙的运用了stack作为数据结构,用stack维护了以最大递增序列,一旦遇到比栈顶小的小矩形高度则开始计算面积。类似的应用将在Ex4中提及。 - -**注意**:计算面积时不要使用~~temp = (i - low) * height[low]~~,因为(i - low)并不是以height[low]为高的。举个栗子: -对于序列1,3,5,4,2的进出栈和运算过程如下: -* 1,3,5顺序入栈 -* 4使得5出栈计算面积 temp = (3 - 1 - 1) * 5 = 5 (~~使用错误方式计算为temp = (3 - 2) * 5 = 5,一致~~) -* 4入栈 -* 2使得4出栈计算面积 temp = (4 - 1 - 1) * 4 = 8 (~~使用错误方式计算为temp = (4 - 3) * 4 = 4,不一致~~) -* ... - -显然错误的计算方式会使得计算过程漏掉中间已被出栈的元素形成的宽度,须知这些已出栈的元素高度肯定大于当前元素,是可以与当前元素形成矩形的。 - -```cpp - int largestRectangleArea(vector &height) { - if(height.empty()) return 0; - stack stk; - int i = 0, max = 0, temp = 0; - while(i<=height.size()-1){ - if(stk.empty()||height[i]>height[stk.top()]){//如果递增或者是第一个,入栈 - stk.push(i); - i++; - }else{ - int low = stk.top();//出栈 - stk.pop(); - if(stk.empty()){//栈为空说明low的左边都大于height[i],同时low到i也是大于height[i]的 - temp = i * height[low]; - }else{ - temp = (i - stk.top() - 1) * height[low]; - } - max = max > temp?max:temp; - } - } - while(!stk.empty()){ - int low = stk.top(); - stk.pop(); - if(stk.empty()){ - temp = height.size() * height[low]; - }else{ - temp = (height.size() - stk.top() -1) * height[low]; - } - max = max > temp?max:temp; - } - - return max; - } -}; -``` - -Ex4:[Maximal Rectangle](http://oj.leetcode.com/problems/maximal-rectangle/) - -这道题有几种解法,但较为巧妙并高效的解法是将其降维至1维,并应用Ex3的算法解决。 -降维举例: -1 1 1 -1 0 1 -0 1 1 -分别以第1行,第1、2行和第1、2、3行为目标,得到 -1 1 1 -> 1 1 1 -> 应用Ex3算法 - -1 1 1 -1 0 1 -> 2 0 2 -> 应用Ex3算法 - -1 1 1 -1 0 1 -0 1 1 -> 0 0 3 -> 应用Ex3算法 -故最大面积为3。 -```cpp -class Solution { -public: - int maximalRectangle(vector > &matrix) { - if(matrix.empty()) return 0; - if(matrix[0].empty()) return 0; - vector temp(matrix[0].size(), 0);//record histogram value - stack stk; - int curIndex = 0, maxArea = 0; - for(int i = 0; i <= matrix.size()-1; i++){ - for(int k = 0; k <= matrix[0].size()-1; k++){ - if(matrix[i][k] == '1'){ - temp[k] += 1; - }else{ - temp[k] = 0; - } - } - for(int j = 0; j <= matrix[0].size()-1;){ - if(stk.empty()|| temp[j]>temp[stk.top()]){ - stk.push(j); - j++; - }else{ - curIndex = stk.top(); - stk.pop(); - int tempArea = 0; - if(!stk.empty()){ - tempArea = (j-stk.top()-1)*temp[curIndex]; - }else{ - tempArea = j*temp[curIndex]; - } - maxArea = maxArea>tempArea?maxArea:tempArea; - } - } - while(!stk.empty()){ - curIndex = stk.top(); - stk.pop(); - int tempArea = 0; - if(!stk.empty()){ - tempArea = (temp.size()-stk.top()-1)*temp[curIndex]; - }else{ - tempArea = temp.size()*temp[curIndex]; - } - maxArea = maxArea>tempArea?maxArea:tempArea; - } - } - return maxArea; - } -}; -``` - -Ex5:[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/)(Removed) - -此题虽然不是计算面积类型题,但因其采用的解题思想与Ex3和Ex4十分相似,即使用一个栈来维护历史状态。更准确的说,“连续的括号”这个状态当且仅当出现无法匹配的')'时才会发生,因此每次匹配成功时分成两种情况来考虑。 -* 栈为空:当前匹配成功位置与上次失配位置之间可能有0到多个匹配成功的括号对,因此i-last -* 栈不为空:尚有未被匹配的'(',此时的失配位置就是栈顶的'('的位置,因此i-lefts.top() - - -```cpp -class Solution { -public: - - int longestValidParentheses(string s) { - int max_len = 0, last = -1; // the position of the last ')' - stack lefts; // keep track of the positions of non-matching '('s - for (int i = 0; i < s.size(); ++i) { - if (s[i] == '(') { - lefts.push(i); - } else { - if (lefts.empty()) { - // no matching left - last = i; - } else { - // find a matching pair - lefts.pop(); - if (lefts.empty()) { - max_len = max(max_len, i - last); - } else { - max_len = max(max_len, i - lefts.top()); - } - } - } - } - return max_len; - } -}; diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 8b41195..db499fd 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -4,7 +4,8 @@ Index: -[Leetcode:Best Time to Buy and Sell Stock III](#Anchor1) -[Leetcode:Decode Ways](#Anchor2) -[LeetCode:Interleaving String](#Anchor3) --[LeetCode:Wildcard Matching](#Anchor3) +-[LeetCode:Wildcard Matching](#Anchor4) +-[LeetCode:Trapping Rain Water](#Anchor5) ------- @@ -195,4 +196,45 @@ public: return dp[pLen][tLen]; } }; -``` \ No newline at end of file +``` + +------- + +-**[LeetCode:Trapping Rain Water](http://oj.leetcode.com/problems/trapping-rain-water/)**([Back to Index](#AnchorIndex)) + +转换思路,将整个容器能够容纳的水划分为每个柱子上方的容水量C[i] + + * C[i] = Min{LeftHighest[i],RightHighest[i]} - A[i] + +其中,LeftHighest[i]是柱子i左侧的最高柱高度(不包括自身),RightHighest[i]是柱子i右侧的最高柱高度(不包括自身),A[i]是柱子i的高度。LeftHighest和RightHighest可以用dp求解,最后对C[i]求和即可得到结果。 + +```cpp +class Solution { +public: + int trap(int A[], int n) { + if(n<=2) return 0; + int units = 0; + vector leftHighest; + leftHighest.resize(n); + leftHighest[0] = 0; + for(int i = 1; i<=n-1; i++){ + if(A[i-1] < leftHighest[i-1]){ + leftHighest[i] = leftHighest[i-1]; + }else{ + leftHighest[i] = A[i-1]; + } + } + + int rightHighest = 0, tempUnit = 0; + for(int j = n-2; j>=1; j--){ + if(A[j+1]>rightHighest){ + rightHighest = A[j+1]; + } + tempUnit = min(leftHighest[j],rightHighest)-A[j]; + if(tempUnit <= 0) continue; + units += tempUnit; + } + return units; + } +}; +``` \ No newline at end of file diff --git a/Greedy Strategy.md b/Greedy Strategy.md index 0c062a8..bdec7ce 100644 --- a/Greedy Strategy.md +++ b/Greedy Strategy.md @@ -2,6 +2,7 @@ Index: -[Cutting digits to make min number](#Anchor1) +-[LeetCode:Container With Most Water](#Anchor2) ------- @@ -55,4 +56,34 @@ int main() } } +``` + +------- + +-**[LeetCode:Container With Most Water](http://oj.leetcode.com/problems/container-with-most-water/) **([Back to Index](#AnchorIndex)) + +题意可理解为:给定一个数组,从中选出两个数字,从而使得以两个数字下标之差为宽、以两个数字较小者为高的矩形面积最大。使用两指针贪心法,总是移动数字较小的指针,贪心策略如下: +* 矩形面积受制于两下标之差,但这个差在两指针靠拢过程中总是缩小的,只能考虑高 +* 高是由较小者决定的,如果移动数字较大的,只能使面积变小(因为宽也变小了),而移动较小的则有可能变大 + +```cpp +class Solution { +public: + int maxArea(vector &height) { + if(height.size() == 0 || height.size() == 1) return 0; + int max = 0, S; + int low = 0, high = height.size()-1; + while(lowmax) max = S; + } + return max; + } +}; ``` \ No newline at end of file diff --git a/Stack.md b/Stack.md index fe3bed7..1d39f23 100644 --- a/Stack.md +++ b/Stack.md @@ -3,6 +3,8 @@ Index: -[Leetcode:Evaluate Reverse Polish Notation](#Anchor1) -[Leetcode:Longest Valid Parentheses](#Anchor2) +-[LeetCode:Largest Rectangle in Histogram](#Anchor3) +-[Maximal Rectangle](#Anchor4) ------- @@ -56,7 +58,6 @@ public class Solution { -**[Leetcode:Longest Valid Parentheses](http://oj.leetcode.com/problems/longest-valid-parentheses/)**([Back to Index](#AnchorIndex)) “连续的括号”这个状态的中断当且仅当出现访问到')'而栈中无'('用于匹配时才会发生。 - 因此每次匹配成功时分成两种情况来考虑。 * 栈为空:当前匹配成功位置与上次失配位置之间可能有0到多个匹配成功的括号对,因此长度为i-last * 栈不为空:尚有未被匹配的'(',此时的失配位置就是栈顶的'('的位置,因此长度i-lefts.top() @@ -89,3 +90,130 @@ public: return max_len; } }; +``` + +------- + +-**[LeetCode:Largest Rectangle in Histogram](http://oj.leetcode.com/problems/largest-rectangle-in-histogram/)**([Back to Index](#AnchorIndex)) +此题如果用暴力求解同样十分繁琐,以下为O(n)解法,注意到 +* 以小矩形A[i]为高的矩形在整个直方图取到的最大面积取决于A[i]右侧的第一个比A[i]小的小矩形A[j]与A[i]形成的宽度 +* 如果小矩形A[i]左侧没有比A[i]小的小矩形,则宽度为0到A[j] +* 如果小矩形A[i]右侧没有比A[i]小的小矩形,且左侧也没有(即全局最小),则宽度为直方图的宽度 + +这里非常巧妙的运用了stack作为数据结构,用stack维护了以最大递增序列,一旦遇到比栈顶小的小矩形高度则开始计算面积。类似的应用将在Ex4中提及。 + +**注意**:计算面积时不要使用~~temp = (i - low) * height[low]~~,因为(i - low)并不是以height[low]为高的。举个栗子: +对于序列1,3,5,4,2的进出栈和运算过程如下: +* 1,3,5顺序入栈 +* 4使得5出栈计算面积 temp = (3 - 1 - 1) * 5 = 5 (~~使用错误方式计算为temp = (3 - 2) * 5 = 5,一致~~) +* 4入栈 +* 2使得4出栈计算面积 temp = (4 - 1 - 1) * 4 = 8 (~~使用错误方式计算为temp = (4 - 3) * 4 = 4,不一致~~) +* ... + +显然错误的计算方式会使得计算过程漏掉中间已被出栈的元素形成的宽度,须知这些已出栈的元素高度肯定大于当前元素,是可以与当前元素形成矩形的。 + +```cpp + int largestRectangleArea(vector &height) { + if(height.empty()) return 0; + stack stk; + int i = 0, max = 0, temp = 0; + while(i<=height.size()-1){ + if(stk.empty()||height[i]>height[stk.top()]){//如果递增或者是第一个,入栈 + stk.push(i); + i++; + }else{ + int low = stk.top();//出栈 + stk.pop(); + if(stk.empty()){//栈为空说明low的左边都大于height[i],同时low到i也是大于height[i]的 + temp = i * height[low]; + }else{ + temp = (i - stk.top() - 1) * height[low]; + } + max = max > temp?max:temp; + } + } + while(!stk.empty()){ + int low = stk.top(); + stk.pop(); + if(stk.empty()){ + temp = height.size() * height[low]; + }else{ + temp = (height.size() - stk.top() -1) * height[low]; + } + max = max > temp?max:temp; + } + + return max; + } +}; +``` + +------- + +-**[Maximal Rectangle](http://oj.leetcode.com/problems/maximal-rectangle/)**([Back to Index](#AnchorIndex)) + +一个较为巧妙并高效的解法是将其降维至一维,并应用[LeetCode:Largest Rectangle in Histogram](#Anchor3)的算法解决。 + +降维举例: +1 1 1 +1 0 1 +0 1 1 +分别以第1行,第1、2行和第1、2、3行为目标,得到 +1 1 1 -> 1 1 1 -> 应用一维算法 + +1 1 1 +1 0 1 -> 2 0 2 -> 应用一维算法 + +1 1 1 +1 0 1 +0 1 1 -> 0 0 3 -> 应用一维算法 +故最大面积为3。 +```cpp +class Solution { +public: + int maximalRectangle(vector > &matrix) { + if(matrix.empty()) return 0; + if(matrix[0].empty()) return 0; + vector temp(matrix[0].size(), 0);//record histogram value + stack stk; + int curIndex = 0, maxArea = 0; + for(int i = 0; i <= matrix.size()-1; i++){ + for(int k = 0; k <= matrix[0].size()-1; k++){ + if(matrix[i][k] == '1'){ + temp[k] += 1; + }else{ + temp[k] = 0; + } + } + for(int j = 0; j <= matrix[0].size()-1;){ + if(stk.empty()|| temp[j]>temp[stk.top()]){ + stk.push(j); + j++; + }else{ + curIndex = stk.top(); + stk.pop(); + int tempArea = 0; + if(!stk.empty()){ + tempArea = (j-stk.top()-1)*temp[curIndex]; + }else{ + tempArea = j*temp[curIndex]; + } + maxArea = maxArea>tempArea?maxArea:tempArea; + } + } + while(!stk.empty()){ + curIndex = stk.top(); + stk.pop(); + int tempArea = 0; + if(!stk.empty()){ + tempArea = (temp.size()-stk.top()-1)*temp[curIndex]; + }else{ + tempArea = temp.size()*temp[curIndex]; + } + maxArea = maxArea>tempArea?maxArea:tempArea; + } + } + return maxArea; + } +}; +``` \ No newline at end of file From 9dc858976a6ac7f6b8bc6816d948705de2a1c70f Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Wed, 29 Oct 2014 21:06:02 +0800 Subject: [PATCH 303/327] merging --- ...eywords Vector Sum, Tree Sum, Other Sum.md | 605 ------------------ 5.Graph&keywords graph.md | 446 ------------- Array & String.md | 367 +++++++++++ Basic Algorithm & Data Structure.md | 378 +++++++++++ Dynamic Programming.md | 15 +- Others.md | 78 +++ Tree & Linkedlist.md | 5 + 7 files changed, 840 insertions(+), 1054 deletions(-) delete mode 100644 3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md delete mode 100644 5.Graph&keywords graph.md diff --git a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md b/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md deleted file mode 100644 index fe8685b..0000000 --- a/3.Sum$keywords Vector Sum, Tree Sum, Other Sum.md +++ /dev/null @@ -1,605 +0,0 @@ -##3.Sum$keywords [Vector Sum](#VectorSumAnchor), [Tree Sum](#TreeSumAnchor), [Other Sum](#OtherSumAnchor) - -###*Vector Sum -Vector Sum问题指的是从给定的数列中寻找和为定值的k个数(k可以为2,3,4以及任意不等)以及由此衍生的问题。对于有序序列的Sum(k=2)问题,可以使用两指针贪心算法;对于无序序列,可以排序再应用上述方法,也可以使用map方法。 - -Ex1:[LeetCode:Two Sum](http://oj.leetcode.com/problems/two-sum/) - -本系列中的基础题,寻找两个数和为给定值。这里展示map方法,即把数列以(value,positon)的形式存入map,然后使用target-numbers[i]查找。注意输出格式。 -```cpp -class Solution { -public: - vector twoSum(vector &numbers, int target) { - map temp; - vector result; - - for(int i = 0;i<=numbers.size()-1;i++){ - temp.insert(pair(numbers.at(i),i+1)); - } - for(int i = 0;i<=numbers.size()-1;i++){ - map::iterator itr = temp.find(target-numbers.at(i)); - if(itr!=temp.end()){ - if(itr->second == i+1){ - continue; - } - if(itr->secondsecond); - result.push_back(i+1); - }else{ - result.push_back(i+1); - result.push_back(itr->second); - } - return result; - } - } - return result; - } -}; -``` - -Ex2:[LeetCode:3Sum](http://oj.leetcode.com/problems/3sum/) - -寻找和为定值的3个数可以通过事先选定一个数降维为two sum问题,同理寻找和为定值的k个数都可以通过多次降维最终通过two sum解决,此题虽然求得是3sum,这里给出ksum的通用解法。其中k==2的递归出口使用的就是两指针贪心法。 - -**注意**,为了使用两指针方法,必须对数列**预先排序**。 -```cpp -class Solution { -public: - vector > threeSum(vector &num) { - vector> ret; - if(num.size()<3) return ret; - sort(num.begin(), num.end()); - ret = findKSum(num, 0, 3, 0); - return ret; - } - - vector > findKSum(vector &num, int start, int k, int target){//require sorted vector - vector> ret; - unordered_set visited; - if(k == 2){ - int i = start, j = num.size()-1; - while(i < j){ - if(visited.find(num[i]) != visited.end()){ - i++; - continue; - } - - int sum = num[i] + num[j]; - if(sum == target){ - vector tempV; - tempV.push_back(num[i]); - tempV.push_back(num[j]); - visited.insert(num[i]); - visited.insert(num[j]); - ret.push_back(tempV); - i++; - j--; - }else if(sum < target){ - i++; - }else{ - j--; - } - } - }else{ - for(int i = start; i <= num.size()-1; i++){ - if(visited.find(num[i]) != visited.end()){ - continue; - }else{ - visited.insert(num[i]); - vector> tempRet = findKSum(num, i+1, k-1, target-num[i]); - if(!tempRet.empty()){ - for(int j = 0; j <= tempRet.size()-1; j++){ - tempRet[j].insert(tempRet[j].begin(), num[i]); - ret.push_back(tempRet[j]); - } - } - } - } - } - return ret; - } -}; -``` -Ex3:[LeetCode:4Sum](http://oj.leetcode.com/problems/4sum/) - -此题仍然可以应用3Sum中通用解法,这里展示的是4sum的map解法,获得(2sum,set(pair(num1,num2)))的map便可以应用类似2Sum的求解方法。 - -```cpp -class Solution { -public: - vector > fourSum(vector &num, int target) { - vector> ret; - set> tempRet; - if(num.size() < 3) return ret; - sort(num.begin(), num.end()); - - unordered_map>> record; - for(int i = 0; i <= num.size()-2; i++){ - for(int j = i+1; j <= num.size()-1; j++){ - int sum = num[i] + num[j]; - unordered_map>>::iterator itr = record.find(sum); - if(itr != record.end()){ - pair p(i, j); - (itr->second).insert(p); - }else{ - set> s; - pair p(i, j); - s.insert(p); - record[sum] = s; - } - } - } - - unordered_set visited; - unordered_map>>::iterator itr1 = record.begin(); - for(;itr1 != record.end(); itr1++){ - if(visited.find(itr1->first) != visited.end()) continue; - visited.insert(itr1->first); - unordered_map>>::iterator itr2 = record.find(target-(itr1->first)); - if(itr2 != record.end()){ - visited.insert(itr2->first); - set>::iterator itr2S = (itr2->second).begin(); - for(; itr2S != (itr2->second).end(); itr2S++){ - set>::iterator itr1S = (itr1->second).begin(); - for(; itr1S != (itr1->second).end(); itr1S++){ - if(itr2S->first == itr1S->first || itr2S->first == itr1S->second || - itr2S->second == itr1S->first || itr2S->second == itr1S->second){ - continue; - }else{ - vector temp; - temp.push_back(num[itr2S->first]); - temp.push_back(num[itr2S->second]); - temp.push_back(num[itr1S->first]); - temp.push_back(num[itr1S->second]); - sort(temp.begin(), temp.end()); - tempRet.insert(temp); - } - } - } - } - } - for(set>::iterator itr = tempRet.begin(); itr != tempRet.end(); itr++){ - ret.push_back(*itr); - } - return ret; - } -}; -``` - -Ex4:[LeetCode:3sum-closest](http://oj.leetcode.com/problems/3sum-closest/) - -与前述题差异在于求解的是和与目标最接近的3个数。仍然应用Ex2中的通用解法,但在k==2的逻辑上略有改动。需要注意的是多了preSum和originT作为辅助实现,结果成立约束条件注意不要把target和originT混用。 -```cpp -class Solution { -public: - int ret; - int threeSumClosest(vector &num, int target) { - sort(num.begin(), num.end()); - ret = num[0]+num[1]+num[2]; - findKSum(num, 0, 0, 3, target, target); - return ret; - } - - void findKSum(vector &num,int preSum, int start, int k, int target, int originT){//require sorted vector - unordered_set visited; - if(k == 2){ - int i = start, j = num.size()-1; - while(i < j){ - int sum = num[i] + num[j]; - if(abs(originT-sum-preSum) < abs(originT-ret)){ - ret = sum + preSum; - if(ret == originT) return; - } - if(sum == target){ - i++; - j--; - }else if(sum < target){ - i++; - }else{ - j--; - } - } - }else{ - for(int i = start; i <= num.size()-1; i++){ - if(visited.find(num[i]) != visited.end()){ - continue; - }else{ - visited.insert(num[i]); - findKSum(num, preSum+num[i], i+1, k-1, target-num[i], originT); - } - } - } - } -}; -``` -Ex5:[LeetCode:Combination Sum](http://oj.leetcode.com/problems/combination-sum/) - -此题要求给定目标和的组合数,对于每个数有不选,选1,选2个...选n个共n+1个选择,注意剪枝。使用Set去重,暂时没考虑在求解过程中自动去重(对candidates排序,看当前数字和前一个数字是否相同进行去重可能可行)。 -```cpp -class Solution { -public: - set > resultSet; - vector > combinationSum(vector &candidates, int target) { - vector > result; - vector temp; - if(candidates.size() == 0) return result; - sort(candidates.begin(),candidates.end()); - compute(temp, candidates, 0, 0, target); - for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ - result.push_back(*itr); - } - return result; - } - - void compute(vector temp, vector& candidates, int index, int currentVal, int target){ - if(index == candidates.size()) return; - - compute(temp, candidates, index+1, currentVal, target); - - for(int i = 1; currentVal + i * candidates[index] <= target; i++){ - temp.push_back(candidates[index]); - if(currentVal + i * candidates[index] == target){ - resultSet.insert(temp); - }else{ - compute(temp, candidates, index+1, currentVal+i*candidates[index], target); - } - } - - return; - } -}; -``` - -Ex6:[LeetCode:Combination Sum II](http://oj.leetcode.com/problems/combination-sum-ii/) - -此题与Ex5区别在于每个数只能用一次,该问题更确切的说是一个01背包问题,使用Set去重,应用以下剪枝方法需要对待选数字升序排序。 - -01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k != M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 - -**选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 - -**不选择k**:若t+r-k>=M&&t+(k+1)<=M,一方面判断剩下的物品还足够填满M,同时同选择k情形判断第k+1个物品是否使得X的解可能存在。 - -```cpp -class Solution { -public: - - set > resultSet; - vector > combinationSum2(vector &num, int target) { - vector > result; - if(num.size() == 0) return result; - vector temp; - temp.clear(); - sort(num.begin(), num.end()); - int rest = 0; - for(int i = 0; i<=num.size()-1; i++){ - rest += num[i]; - } - compute(temp, num, 0, rest, target); - for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ - result.push_back(*itr); - } - - return result; - } - - - //优化剪枝的递归函数 92ms - void compute(vector& temp, vector num, int currentVal, int restVal, int target){ - if(num.size() == 0) return; - - if(currentVal + num[0] == target){ - temp.push_back(num[0]); - resultSet.insert(temp); - temp.pop_back(); - return; - } - - if(num.size() == 1) return; - - if(currentVal + num[0] + num[1] <= target){ - temp.push_back(num[0]); - compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); - temp.pop_back(); - } - - if(currentVal + restVal - num[0] >= target && currentVal + num[1] <= target){ - compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); - } - - return; - } - - - //未优化剪枝的递归函数 1160ms - /* - void compute(vector& temp, vector num, int currentVal, int restVal, int target){ - if(num.size() == 0) return; - - if(currentVal + num[0] == target){ - temp.push_back(num[0]); - resultSet.insert(temp); - temp.pop_back(); - return; - } - - if(currentVal + num[0] <= target){ - temp.push_back(num[0]); - compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); - temp.pop_back(); - } - - compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); - - return; - }*/ -}; -``` - -###*Tree Sum - -Tree Sum指在树节点中进行的有条件求和问题,对于树的遍历,基本思路是DFS或BFS,以下例题展示这些方法是如何应用的。 - -Ex7:[LeetCode:Binary Tree Maximum Path Sum](http://oj.leetcode.com/problems/binary-tree-maximum-path-sum/) - -本题的解答写的比较繁琐,以后更新简洁解法。核心思想是DFS递归函数返回的是当前节点的最大路径和P,注意这里所指的最大路径为当前节点到其叶子节点的简单子路径。同时使用一个全局变量或传引用变量记录路径最大值max,当前节点其能形成的最大子路径有四种情况: -* 左孩子和右孩子都不存在,最大值为Vroot -* 左孩子不存在,最大值为Vroot(如果P < 0)或Vroot+P -* 右孩子不存在,最大值为Vroot(如果P < 0)或Vroot+P -* 左孩子和右孩子都存在,最大值为Vroot、Vroot+P、Vroot+P、Vroot+P+P情形之一 - -```cpp -class Solution { -public: - int maxSum = 0x80000000; - int maxPathSum(TreeNode *root) { - if(root == NULL) return 0; - int val = recursion(root); - return val>maxSum?val:maxSum; - } - - int recursion(TreeNode* root){ - if(root == NULL) return 0; - int leftVal = 0, rightVal = 0, temp = 0; - if(root->left == NULL && root->right == NULL){ - if(root->val > maxSum) maxSum = root->val; - return root->val; - } - if(root->left == NULL){ - rightVal = recursion(root->right); - temp = rightVal < 0?root->val:root->val+rightVal; - if(temp > maxSum) maxSum = temp; - return temp; - } - if(root->right == NULL){ - leftVal = recursion(root->left); - temp = leftVal < 0?root->val:root->val+leftVal; - if(temp > maxSum) maxSum = temp; - return temp; - } - - rightVal = recursion(root->right); - leftVal = recursion(root->left); - if(root->val > maxSum) maxSum = root->val; - if(root->val+rightVal > maxSum) maxSum = root->val+rightVal; - if(root->val+leftVal > maxSum) maxSum = root->val+leftVal; - if(leftVal + rightVal + root->val > maxSum){ - maxSum = leftVal + rightVal + root->val; - } - if(leftVal < 0 && rightVal < 0){ - return root->val; - }else{ - return leftVal>rightVal?leftVal+root->val:rightVal+root->val; - } - } -}; -``` -Ex8:[LeetCode:Sum Root to Leaf Numbers](http://oj.leetcode.com/problems/sum-root-to-leaf-numbers/) - -非常简单的一道题,利用DFS不断累加和值,直到叶子节点将其加入总和。 - -```cpp -class Solution { -public: - int total; - int sumNumbers(TreeNode *root) { - total = 0; - if(root == NULL) return 0; - sum(root, 0); - return total; - } - - void sum(TreeNode * root, int upToSum){ - if(root == NULL){ - return; - } - - if(root->left == NULL && root->right == NULL){ - total += upToSum * 10 + root->val; - return; - } - if(root->left == NULL){ - sum(root->right, upToSum * 10 + root->val); - return; - } - if(root->right == NULL){ - sum(root->left, upToSum * 10 + root->val); - return; - } - sum(root->left, upToSum * 10 + root->val); - sum(root->right, upToSum *10 + root->val); - return; - } -}; -``` - -Ex9:[LeetCode:Path Sum](http://oj.leetcode.com/problems/path-sum/) - -同样非常简单的一道题,DFS直到叶子节点,判断: -* 左孩子和右孩子都不存在,叶子节点,判等 -* 左孩子不存在,取决于b右孩子 -* 右孩子不存在,取决于b左孩子 -* 左孩子和右孩子都存在,取决于b左孩子&&b右孩子 - -```cpp -class Solution { -public: - bool hasPathSum(TreeNode *root, int sum) { - if(root == NULL) return false; - if(root->left == NULL && root->right == NULL){ - if(sum == root->val){ - return true; - }else{ - return false; - } - } - if(hasPathSum(root->left,sum-root->val)) return true; - if(hasPathSum(root->right,sum-root->val)) return true; - return false; - } -}; -``` - -Ex10:[LeetCode:Path Sum II](http://oj.leetcode.com/problems/path-sum-ii/) - -思路与Ex9一样,额外使用一个Stack来记录当前路径。 -```cpp -class Solution { -public: - vector > result; - vector temp; - vector > pathSum(TreeNode *root, int sum) { - if(root == NULL) return result; - temp.push_back(root->val); - if(root->left == NULL && root->right == NULL){ - if(root->val == sum){ - result.push_back(temp); - } - } - if(root->left != NULL) pathSum(root->left,sum-root->val); - if(root->right != NULL) pathSum(root->right,sum-root->val); - temp.pop_back(); - return result; - } -}; -``` - -###*Other Sum -该小节收录了一些不属于上两类的经典求和问题。 - -Ex11:[LeetCode:Maximum Subarray](http://oj.leetcode.com/problems/maximum-subarray/) - -经典问题,求解连续子数组最大和。核心思想是维护一个当前和值sum,如果sum比max大,则更新;如果sum小于0,则对后面的子数组没有贡献,肯定不属于可行解的一部分,舍去,最终求出结果。 -```cpp -class Solution { -public: - int maxSubArray(int A[], int n) { - int sum = 0, max = INT_MIN; - for(int i = 0; i <= n-1; i++){ - sum += A[i]; - if(sum > max){ - max = sum; - } - if(sum < 0){ - sum = 0; - } - } - return max; - } -}; -``` - -Ex12: Maximum SubMatrix - -求解一个二维数组A[N][M]拥有最大和值的子数组,如 -1 -1 -1 --1 5 7 --1 6 8 -结果子数组为 -5 7 -6 8 -和值为26 - -考虑将二维数组降维为一维处理,可以获得O(N2M)的时间复杂度。具体做法是使用s,e作为上下界确定矩形的高,将s和e之间的**一列元素的和**等同于一维问题的一个元素。对于特定的s和e,应用一维的O(n)算法求出特定s和e情形下的最大值;穷举s和e的组合,求出全局的最大值。使用dp的方法事先求解列和,dp[i][j]表示第j列中第0个至第i个的和值。 - -```cpp -int Solution(vector > input){ - if(input.empty()) return INT_MIN; - if(input[0].empty()) return INT_MIN; - - int ret = INT_MIN; - int row = input.size(), col = input[0].size(); - - int dp[row][col]; - for(int i = 0; i <= row-1; i++){ - for(int j = 0; j <= col-1;j++){ - if(i == 0){ - dp[i][j] = input[i][j]; - }else{ - dp[i][j] = input[i][j] + dp[i-1][j]; - } - } - } - - int A[col]; - for(int s = 0; s <= row-1; s++){ - for(int e = s; e <= row-1; e++){ - for(int k = 0; k <= col-1; k++){ - if(s == 0){ - A[k] = dp[e][k]; - }else{ - A[k] = dp[e][k] - dp[s-1][k]; - } - } - int temp = MaxSubArray(A, col); - ret = temp > ret?temp:ret; - } - } - return ret; -} - -int MaxSubArray(int A[], int n){ - int sum = 0, max = INT_MIN; - for(int i = 0; i <= n-1; i++){ - sum += A[i]; - if(sum > max){ - max = sum; - } - if(sum < 0){ - sum = 0; - } - } - return max; -} -``` -Ex13:Count number of 1 from 1 to n - -统计从1到n共n个十进制整数中包含1的总数,如输入n=11,统计结果为4(1,10,11)。 -核心思路是按位统计1的个数,以一个例子来说明规则是如何被应用的。统计百位上1的个数: -* 对于十进制数12035,由于百位上的数是'0',故只由百位前面的“高位”决定 - + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) -* 对于十进制数12135,由于百位上的数是'1',故由百位前面的“高位”和百位后面的“低位”共同决定 - + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) - + 35 + 1个(12100~12135) -* 对于十进制数12512,由于百位上的数是'5',故由百位前面的“高位”决定 - + (12 + 1) * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199,12100~12199) -由此可以看出统计规则主要是在统计第x位时,获得x的“高位”和低位,并根据x与1的关系分类计算,代码如下。 - -```cpp -int countOnes(int n){ - int ret = 0, factor = 1; - int higher = 0, cur = 0, lower = 0; - while(n / factor != 0){//n == 12135 - higher = n/(factor*10);//12, when factor == 100 - cur = (n/factor)%10;//1, when factor == 100 - lower = n%factor;//35, when factor == 100 - switch(cur){ - case 0: ret += higher * factor; break; - case 1: ret += higher * factor + lower + 1; break; - default: ret += (higher + 1) * factor; break; - } - factor *= 10; - } - return ret; -} -``` diff --git a/5.Graph&keywords graph.md b/5.Graph&keywords graph.md deleted file mode 100644 index b76b19e..0000000 --- a/5.Graph&keywords graph.md +++ /dev/null @@ -1,446 +0,0 @@ -##*5.Graph&keywords graph - -Ex1:Prim:求一个图的最小生成树 - -标准的prim算法,用邻接矩阵来表示图,用一个数组来表示最小生成树 -```java - -public class Main { - int num; - int[][] dis; - - public Main(int num, int[][] dis) { - this.num = num; - this.dis = dis; - } - - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - int n = in.nextInt(); - while (n-- != 0) { - int num = in.nextInt(); - int[][] dis = new int[num + 1][num + 1]; - for (int i = 1; i <= num; i++) - for (int j = 1; j <= num; j++) - dis[i][j] = in.nextInt(); - - Main m = new Main(num, dis); - int result = m.prim(); - System.out.println(result); - } - } - - public int prim() { - boolean[] in = new boolean[num + 1]; - in[1] = true; - int max = 0; - while (!allin(in)) { - int min = Integer.MAX_VALUE; - int target = 0; - for (int i = 1; i <= num; i++) - if (in[i]) - for (int j = 1; j <= num; j++) - if (i != j && !in[j] && dis[i][j] < min) { - min = dis[i][j]; - target = j; - } - in[target] = true; - if (min > max) - max = min; - } - - return max; - } - - public boolean allin(boolean[] in) { - for (boolean a : in) - if (!a) - return false; - - return true; - } -} -``` - -Ex2:Dijkstra:求某个定点到其他所有顶点的单源最短路径 - -标准的Dijkstra算法,用邻接矩阵来表示图,每次加入一个点并更新最小距离 -```java -public class Dijkstra { - static int M = 10000; - - public static void main(String[] args) { - // TODO Auto-generated method stub - int[][] weight1 = {// 邻接矩阵 - { 0, 3, 2000, 7, M }, { 3, 0, 4, 2, M }, { M, 4, 0, 5, 4 }, - { 7, 2, 5, 0, 6 }, { M, M, 4, 6, 0 } }; - - int[][] weight2 = { { 0, 10, M, 30, 100 }, { M, 0, 50, M, M }, - { M, M, 0, M, 10 }, { M, M, 20, 0, 60 }, { M, M, M, M, 0 } }; - int start = 0; - int[] shortPath = Dijsktra(weight1, start); - - for (int i = 0; i < shortPath.length; i++) - System.out.println("从" + start + "出发到" + i + "的最短距离为:" - + shortPath[i]); - } - - public static int[] Dijsktra(int[][] weight, int start) { - // 接受一个有向图的权重矩阵,和一个起点编号start(从0编号,顶点存在数组中) - // 返回一个int[] 数组,表示从start到它的最短路径长度 - int n = weight.length; // 顶点个数 - int[] shortPath = new int[n]; // 存放从start到其他各点的最短路径 - String[] path = new String[n]; // 存放从start到其他各点的最短路径的字符串表示 - for (int i = 0; i < n; i++) - path[i] = new String(start + "-->" + i); - int[] visited = new int[n]; // 标记当前该顶点的最短路径是否已经求出,1表示已求出 - - // 初始化,第一个顶点求出 - shortPath[start] = 0; - visited[start] = 1; - - for (int count = 1; count <= n - 1; count++) // 要加入n-1个顶点 - { - int k = -1; // 选出一个距离初始顶点start最近的未标记顶点 - int dmin = Integer.MAX_VALUE; - for (int i = 0; i < n; i++) { - if (visited[i] == 0 && weight[start][i] < dmin) { - dmin = weight[start][i]; - k = i; - } - } - // System.out.println("k="+k); - // 将新选出的顶点标记为已求出最短路径,且到start的最短路径就是dmin - shortPath[k] = dmin; - visited[k] = 1; - // 以k为中间点,修正从start到未访问各点的距离 - for (int i = 0; i < n; i++) { - if (visited[i] == 0 - && weight[start][k] + weight[k][i] < weight[start][i]) { - weight[start][i] = weight[start][k] + weight[k][i]; - path[i] = path[k] + "-->" + i; - } - } - } - for (int i = 0; i < n; i++) - System.out.println("从" + start + "出发到" + i + "的最短路径为:" + path[i]); - System.out.println("====================================="); - - return shortPath; - } -} -``` - -Ex3:Floyd:求每一个顶点到其他所有定点的最短长度 - -标准的Floyd算法。 -```java -public class Floyd { - - public double[][] matrix; - - public Floyd(double[][] mat) { - matrix = mat; - } - - public double[][] doFloyd() { - int size = InitMatrix.size; - for (int k = 1; k <= size; k++) - for (int i = 1; i <= size; i++) - for (int j = 1; j <= size; j++) - if (matrix[i][j] > matrix[i][k] + matrix[k][j]) - matrix[i][j] = matrix[i][k] + matrix[k][j]; - return matrix; - } -} -``` - -Ex4:四色定理:用颜色去标记图的所有顶点,要求相邻的顶点颜色不同,问最少多少种颜色。 - -用数字代表颜色。遍历图,对于每个节点,记录与它相邻节点的颜色,然后选出这些颜色中不包含的、数字最小的颜色,涂在当前节点。 -```java -public class Solution { - public void FourColor(String[] ss) { - int len = ss.length; - boolean[][] map = new boolean[len + 1][27]; - for (String s : ss) - for (int i = 2; i < s.length(); i++) - map[s.charAt(0) - 'A' + 1][s.charAt(i) - 'A' + 1] = true; - int max = 0; - - int[] color = new int[27]; - for (int i = 1; i <= len; i++) { - boolean[] visit = new boolean[len + 1]; - for (int j = 1; j <= len; j++) - if (map[i][j])//看j是否是i的邻接节点 - if (color[j] != 0)//如果j被涂色了 - visit[color[j]] = true;//将该颜色做标记 - for (int j = 1; j <= len; j++) - if (!visit[j]) {//从中选出序号最小的未被使用的颜色 - color[i] = j;//涂色 - max = Math.max(max, j);//目前用的颜色数量的最大值 - break; - } - } - - System.out.println(max); - } - - public static void main(String[] args) { - Solution m = new Solution(); - // String[] ss = { "A:BCD", "B:ACD", "C:ABD", "D:ABC" }; - String[] ss = { "A:BC", "B:ACD", "C:ABD", "D:BC" }; - m.FourColor(ss); - } -} -``` - -Ex5:[Leetcode:Palindrome Partitioning II](http://oj.leetcode.com/problems/palindrome-partitioning-ii/) - -此题中先用到了dp标记(详见[2.String dp and Array dp](2.String dp and Array dp$keywords dp.md )),然后用Dijkstra算法计算从0到末尾的最短距离。 - -Added by [@sc703bupt](https://github.com/sc703bupt):这道题的理解是将从0到i的切分次数看成图中的路径距离,对于刚刚加入确定集合的节点i,其对剩余未加入确定集合的节点j的松弛操作为data[j] = min{data[j], data[i]+1},前提是isPalindrome[i][j]为true。 -```java -public class Solution { - public int minCut(String s) { - //回文串的判定二维数组 - boolean[][] isPalindrome = new boolean[s.length()+1][s.length()+1]; - for (int i=0; i -using namespace std; -int times=1,low[1000],dfn[1000]; - -int stack[1000],top=0; - -bool instack[1000]={false}; - -struct LIST -{ - int v; - LIST *next; -}; - -LIST *head[1000]={NULL}; - -int min(int a,int b) -{ - if(anext) /*遍历V能直接到达的点*/ - if(!dfn[p->v]) /*如果v的邻接点没有入过栈*/ - { - tarjan(p->v); - low[v]=min(low[v],low[p->v]); /*如果v能直接到达的这个点没在栈中,v的最早祖先为他们中的较小值*/ - } - else if(instack[p->v]) /*如果在栈中*/ - low[v]=min(low[v],dfn[p->v]); /*如果在栈中,则v的最早祖先是他的序号和那个点的序号较小的*/ - - if(dfn[v]==low[v]) /*如果dfn[v]和low[v]相等,则说明v点是其所属强连通分支DFS遍历起点,这个强连通分支说有点都在v点之上*/ - { - cout<<"{ "; - do - { - v=stack[--top]; - instack[v]=false; - cout<>n; - - memset(dfn,0,sizeof(char)*4000); - for(i=1;i<=n;i++) - { - cout<>m; - cout<<"输入每个邻接点编号"; - LIST *rear=head[i]; - for(j=0;jnext=new LIST; - rear=rear->next; - } - rear->next=NULL; - cin>>rear->v; - } - } - - for(i=1;i<=n;i++) - if(!dfn[i]) /*如果i没有入过栈*/ - tarjan(i); - - system("pause"); - return 0; -} -``` - -Ex7:拓扑排序:拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。 -首先收集所有入度为0的顶点。将入度为0的顶点加入结果集。之后移除这个顶点连接的所有边,加入入度为零的顶点,如此循环。若加入结果集的节点个数少于总个数,说明有环,无法导出拓扑序列 -```cpp - - #include - #include - #include - #include - using namespace std; - //toposort的三种情况 - const int N=27; - int n,m; - int graph[N][N],indegree[N],list[N]; - - int toposort(int n) - { - int in[N]; - memcpy(in,indegree,sizeof(indegree)); //复制入度数组,以免对主函数中的indegree有影响 - stack s; - int i; - for(i=0;i1) - flag=1; //序列不确定 - t=s.top(); - s.pop(); - list[j++]=t; //记录出栈的数字 - for(i=0;i @@ -638,4 +645,364 @@ public: return (int) sum; } }; +``` + +------- + +-**[LeetCode:Maximum Subarray](http://oj.leetcode.com/problems/maximum-subarray/)**([Back to Index](#AnchorIndex)) + +经典问题,求解连续子数组最大和。核心思想是维护一个当前和值sum,如果sum比max大,则更新;如果sum小于0,则对后面的子数组没有贡献,肯定不属于可行解的一部分,舍去,最终求出结果。 +```cpp +class Solution { +public: + int maxSubArray(int A[], int n) { + int sum = 0, max = INT_MIN; + for(int i = 0; i <= n-1; i++){ + sum += A[i]; + if(sum > max){ + max = sum; + } + if(sum < 0){ + sum = 0; + } + } + return max; + } +}; +``` + +------- + +-**Maximum SubMatrix**([Back to Index](#AnchorIndex)) + +求解一个二维数组A[N][M]拥有最大和值的子数组,如 +1 -1 -1 +-1 5 7 +-1 6 8 +结果子数组为 +5 7 +6 8 +和值为26 + +考虑将二维数组降维为一维处理,可以获得O(N2M)的时间复杂度。具体做法是使用s,e作为上下界确定矩形的高,将s和e之间的**一列元素的和**等同于一维问题的一个元素。对于特定的s和e,应用一维的O(n)算法求出特定s和e情形下的最大值;穷举s和e的组合,求出全局的最大值。使用dp的方法事先求解列和,dp[i][j]表示第j列中第0个至第i个的和值。 + +```cpp +int Solution(vector > input){ + if(input.empty()) return INT_MIN; + if(input[0].empty()) return INT_MIN; + + int ret = INT_MIN; + int row = input.size(), col = input[0].size(); + + int dp[row][col]; + for(int i = 0; i <= row-1; i++){ + for(int j = 0; j <= col-1;j++){ + if(i == 0){ + dp[i][j] = input[i][j]; + }else{ + dp[i][j] = input[i][j] + dp[i-1][j]; + } + } + } + + int A[col]; + for(int s = 0; s <= row-1; s++){ + for(int e = s; e <= row-1; e++){ + for(int k = 0; k <= col-1; k++){ + if(s == 0){ + A[k] = dp[e][k]; + }else{ + A[k] = dp[e][k] - dp[s-1][k]; + } + } + int temp = MaxSubArray(A, col); + ret = temp > ret?temp:ret; + } + } + return ret; +} + +int MaxSubArray(int A[], int n){ + int sum = 0, max = INT_MIN; + for(int i = 0; i <= n-1; i++){ + sum += A[i]; + if(sum > max){ + max = sum; + } + if(sum < 0){ + sum = 0; + } + } + return max; +} +``` + +------- + +-**[LeetCode:Two Sum](http://oj.leetcode.com/problems/two-sum/)**([Back to Index](#AnchorIndex)) + +基础题,寻找两个数和为给定值,可以采用两指针贪心法。这里展示map方法,即把数列以(value,positon)的形式存入map,然后使用target-numbers[i]查找。注意输出格式。 +```cpp +class Solution { +public: + vector twoSum(vector &numbers, int target) { + map temp; + vector result; + + for(int i = 0;i<=numbers.size()-1;i++){ + temp.insert(pair(numbers.at(i),i+1)); + } + for(int i = 0;i<=numbers.size()-1;i++){ + map::iterator itr = temp.find(target-numbers.at(i)); + if(itr!=temp.end()){ + if(itr->second == i+1){ + continue; + } + if(itr->secondsecond); + result.push_back(i+1); + }else{ + result.push_back(i+1); + result.push_back(itr->second); + } + return result; + } + } + return result; + } +}; +``` + +------- + +-**[LeetCode:3Sum](http://oj.leetcode.com/problems/3sum/)**([Back to Index](#AnchorIndex)) + +寻找和为定值的3个数可以通过事先选定一个数降维为two sum问题,同理寻找和为定值的k个数都可以通过多次降维最终通过two sum解决,此题虽然求得是3sum,这里给出ksum的通用解法。其中k==2的递归出口使用的就是两指针贪心法。 + +**注意**,为了使用两指针方法,必须对数列**预先排序**。 +```cpp +class Solution { +public: + vector > threeSum(vector &num) { + vector> ret; + if(num.size()<3) return ret; + sort(num.begin(), num.end()); + ret = findKSum(num, 0, 3, 0); + return ret; + } + + vector > findKSum(vector &num, int start, int k, int target){//require sorted vector + vector> ret; + unordered_set visited; + if(k == 2){ + int i = start, j = num.size()-1; + while(i < j){ + if(visited.find(num[i]) != visited.end()){ + i++; + continue; + } + + int sum = num[i] + num[j]; + if(sum == target){ + vector tempV; + tempV.push_back(num[i]); + tempV.push_back(num[j]); + visited.insert(num[i]); + visited.insert(num[j]); + ret.push_back(tempV); + i++; + j--; + }else if(sum < target){ + i++; + }else{ + j--; + } + } + }else{ + for(int i = start; i <= num.size()-1; i++){ + if(visited.find(num[i]) != visited.end()){ + continue; + }else{ + visited.insert(num[i]); + vector> tempRet = findKSum(num, i+1, k-1, target-num[i]); + if(!tempRet.empty()){ + for(int j = 0; j <= tempRet.size()-1; j++){ + tempRet[j].insert(tempRet[j].begin(), num[i]); + ret.push_back(tempRet[j]); + } + } + } + } + } + return ret; + } +}; +``` + +------- + +-**[LeetCode:4Sum](http://oj.leetcode.com/problems/4sum/)**([Back to Index](#AnchorIndex)) + +选定区间的两个端点,对区间应用Two Sum算法,时间复杂度O(n^3)。 + +class Solution { +public: + vector > fourSum(vector &num, int target) { + set > tempRet; + int n = num.size(); + sort(num.begin(), num.end()); + for(int s = 0; s <= n-1; s++){ + for(int e = s+3; e <= n-1; e++){ + int a = s+1, b = e-1; + while(a < b){ + int sum = num[s] + num[e] + num[a] + num[b]; + if(sum == target){ + vector temp; + temp.push_back(num[s]); + temp.push_back(num[a]); + temp.push_back(num[b]); + temp.push_back(num[e]); + tempRet.insert(temp); + a++; + b--; + }else if(sum < target){ + a++; + }else{ + b--; + } + } + } + } + vector > ret(tempRet.begin(), tempRet.end()); + return ret; + } +}; +``` + +------- + +-**[LeetCode:Combination Sum](http://oj.leetcode.com/problems/combination-sum/)**([Back to Index](#AnchorIndex)) + +此题要求给定目标和的组合数,对于每个数有不选,选1,选2个...选n个共n+1个选择,注意剪枝。使用Set去重,暂时没考虑在求解过程中自动去重(对candidates排序,看当前数字和前一个数字是否相同进行去重可能可行)。 +```cpp +class Solution { +public: + set > resultSet; + vector > combinationSum(vector &candidates, int target) { + vector > result; + vector temp; + if(candidates.size() == 0) return result; + sort(candidates.begin(),candidates.end()); + compute(temp, candidates, 0, 0, target); + for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ + result.push_back(*itr); + } + return result; + } + + void compute(vector temp, vector& candidates, int index, int currentVal, int target){ + if(index == candidates.size()) return; + + compute(temp, candidates, index+1, currentVal, target); + + for(int i = 1; currentVal + i * candidates[index] <= target; i++){ + temp.push_back(candidates[index]); + if(currentVal + i * candidates[index] == target){ + resultSet.insert(temp); + }else{ + compute(temp, candidates, index+1, currentVal+i*candidates[index], target); + } + } + + return; + } +}; +``` + +------- + +-**[LeetCode:Combination Sum II](http://oj.leetcode.com/problems/combination-sum-ii/)**([Back to Index](#AnchorIndex)) + +此题与Ex5区别在于每个数只能用一次,该问题更确切的说是一个01背包问题,使用Set去重,应用以下剪枝方法需要对待选数字升序排序。 + +01的背包方法剪枝:下述方法的前提是物品价值Wi是升序的(降序也可以使用,较为麻烦)。X是解向量,t=Σ(1...k-1)Wi*Xi,即为k-1个已选的物品的总价值,r=Σ(k...n)Wi,即为剩余物品的总价值在t+k != M的前提下,X={X1,X2...X(k-1),Xk,0...0}已经可以判定不是有效解,只能看第k+1的物品的情况,考虑第k个物品的两种情况 + + **选择k**:若t+Wk+W(k+1)<=M,则说明选入作为剩余物品中价值最小的物品W(k+1)使得X的解可能存在(反过来说如果t+Wk+W(k+1)>M则说明t+Wk(k+1..n)Wi*Xi>M,则X无解),令Xk =1,递归左儿子;否则剪枝。 + + **不选择k**:若t+r-k>=M&&t+(k+1)<=M,一方面判断剩下的物品还足够填满M,同时同选择k情形判断第k+1个物品是否使得X的解可能存在。 + +```cpp +class Solution { +public: + + set > resultSet; + vector > combinationSum2(vector &num, int target) { + vector > result; + if(num.size() == 0) return result; + vector temp; + temp.clear(); + sort(num.begin(), num.end()); + int rest = 0; + for(int i = 0; i<=num.size()-1; i++){ + rest += num[i]; + } + compute(temp, num, 0, rest, target); + for(set >::iterator itr = resultSet.begin(); itr != resultSet.end(); itr++){ + result.push_back(*itr); + } + + return result; + } + + + //优化剪枝的递归函数 92ms + void compute(vector& temp, vector num, int currentVal, int restVal, int target){ + if(num.size() == 0) return; + + if(currentVal + num[0] == target){ + temp.push_back(num[0]); + resultSet.insert(temp); + temp.pop_back(); + return; + } + + if(num.size() == 1) return; + + if(currentVal + num[0] + num[1] <= target){ + temp.push_back(num[0]); + compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); + temp.pop_back(); + } + + if(currentVal + restVal - num[0] >= target && currentVal + num[1] <= target){ + compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); + } + + return; + } + + + //未优化剪枝的递归函数 1160ms + /* + void compute(vector& temp, vector num, int currentVal, int restVal, int target){ + if(num.size() == 0) return; + + if(currentVal + num[0] == target){ + temp.push_back(num[0]); + resultSet.insert(temp); + temp.pop_back(); + return; + } + + if(currentVal + num[0] <= target){ + temp.push_back(num[0]); + compute(temp, vector(num.begin()+1, num.end()), currentVal+num[0], restVal-num[0], target); + temp.pop_back(); + } + + compute(temp, vector(num.begin()+1, num.end()), currentVal, restVal-num[0], target); + + return; + }*/ +}; ``` \ No newline at end of file diff --git a/Basic Algorithm & Data Structure.md b/Basic Algorithm & Data Structure.md index ccd12a8..e26d70e 100644 --- a/Basic Algorithm & Data Structure.md +++ b/Basic Algorithm & Data Structure.md @@ -6,6 +6,11 @@ Index: -[Nonrecursive Tree Traversal](#Anchor3) -[KMP](#Anchor4) -[QuickSort in Linklist](#Anchor5) +-[Topological Sort](#Anchor6) +-[Prim](#Anchor7) +-[Dijkstra](#Anchor8) +-[Floyd](#Anchor9) +-[Tarjan](#Anchor10) ------- @@ -219,6 +224,7 @@ using namespace std; class ListNode{ public: + int val; ListNode * next; ListNode(int _val):val(_val),next(NULL){} @@ -272,4 +278,376 @@ ListNode * quickSort(ListNode * head){ midTail->next = backRet; return ret; } +``` + +------- + +-**Topological Sort**([Back to Index](#AnchorIndex)) + +拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。 + +首先收集所有入度为0的顶点。将入度为0的顶点加入结果集。之后移除这个顶点连接的所有边,加入入度为零的顶点,如此循环。若加入结果集的节点个数少于总个数,说明有环,无法导出拓扑序列。 + +另外,拓扑排序算法是非常好的判断有向图中是否有环存在的算法,对于连通图和非连通图均适用。 +```cpp + + #include + #include + #include + #include + using namespace std; + //toposort的三种情况 + const int N=27; + int n,m; + int graph[N][N],indegree[N],list[N]; + + int toposort(int n) + { + int in[N]; + memcpy(in,indegree,sizeof(indegree)); //复制入度数组,以免对主函数中的indegree有影响 + stack s; + int i; + for(i=0;i1) + flag=1; //序列不确定 + t=s.top(); + s.pop(); + list[j++]=t; //记录出栈的数字 + for(i=0;i +-**Prim**([Back to Index](#AnchorIndex)) + +标准的prim算法,即求一个图的最小生成树。用邻接矩阵来表示图,用一个数组来表示最小生成树。 + +```java + +public class Main { + int num; + int[][] dis; + + public Main(int num, int[][] dis) { + this.num = num; + this.dis = dis; + } + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n = in.nextInt(); + while (n-- != 0) { + int num = in.nextInt(); + int[][] dis = new int[num + 1][num + 1]; + for (int i = 1; i <= num; i++) + for (int j = 1; j <= num; j++) + dis[i][j] = in.nextInt(); + + Main m = new Main(num, dis); + int result = m.prim(); + System.out.println(result); + } + } + + public int prim() { + boolean[] in = new boolean[num + 1]; + in[1] = true; + int max = 0; + while (!allin(in)) { + int min = Integer.MAX_VALUE; + int target = 0; + for (int i = 1; i <= num; i++) + if (in[i]) + for (int j = 1; j <= num; j++) + if (i != j && !in[j] && dis[i][j] < min) { + min = dis[i][j]; + target = j; + } + in[target] = true; + if (min > max) + max = min; + } + + return max; + } + + public boolean allin(boolean[] in) { + for (boolean a : in) + if (!a) + return false; + + return true; + } +} +``` + +------- + +-**Dijkstra**([Back to Index](#AnchorIndex)) + +标准的Dijkstra算法,即求某个定点到其他所有顶点的单源最短路径。用邻接矩阵来表示图,每次加入一个点并更新最小距离 +```java +public class Dijkstra { + static int M = 10000; + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[][] weight1 = {// 邻接矩阵 + { 0, 3, 2000, 7, M }, { 3, 0, 4, 2, M }, { M, 4, 0, 5, 4 }, + { 7, 2, 5, 0, 6 }, { M, M, 4, 6, 0 } }; + + int[][] weight2 = { { 0, 10, M, 30, 100 }, { M, 0, 50, M, M }, + { M, M, 0, M, 10 }, { M, M, 20, 0, 60 }, { M, M, M, M, 0 } }; + int start = 0; + int[] shortPath = Dijsktra(weight1, start); + + for (int i = 0; i < shortPath.length; i++) + System.out.println("从" + start + "出发到" + i + "的最短距离为:" + + shortPath[i]); + } + + public static int[] Dijsktra(int[][] weight, int start) { + // 接受一个有向图的权重矩阵,和一个起点编号start(从0编号,顶点存在数组中) + // 返回一个int[] 数组,表示从start到它的最短路径长度 + int n = weight.length; // 顶点个数 + int[] shortPath = new int[n]; // 存放从start到其他各点的最短路径 + String[] path = new String[n]; // 存放从start到其他各点的最短路径的字符串表示 + for (int i = 0; i < n; i++) + path[i] = new String(start + "-->" + i); + int[] visited = new int[n]; // 标记当前该顶点的最短路径是否已经求出,1表示已求出 + + // 初始化,第一个顶点求出 + shortPath[start] = 0; + visited[start] = 1; + + for (int count = 1; count <= n - 1; count++) // 要加入n-1个顶点 + { + int k = -1; // 选出一个距离初始顶点start最近的未标记顶点 + int dmin = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (visited[i] == 0 && weight[start][i] < dmin) { + dmin = weight[start][i]; + k = i; + } + } + // System.out.println("k="+k); + // 将新选出的顶点标记为已求出最短路径,且到start的最短路径就是dmin + shortPath[k] = dmin; + visited[k] = 1; + // 以k为中间点,修正从start到未访问各点的距离 + for (int i = 0; i < n; i++) { + if (visited[i] == 0 + && weight[start][k] + weight[k][i] < weight[start][i]) { + weight[start][i] = weight[start][k] + weight[k][i]; + path[i] = path[k] + "-->" + i; + } + } + } + for (int i = 0; i < n; i++) + System.out.println("从" + start + "出发到" + i + "的最短路径为:" + path[i]); + System.out.println("====================================="); + + return shortPath; + } +} +``` + +------- + +-**Floyd**([Back to Index](#AnchorIndex)) + +标准的Floyd算法,即求每一个顶点到其他所有定点的最短长度。 + +```java +public class Floyd { + + public double[][] matrix; + + public Floyd(double[][] mat) { + matrix = mat; + } + + public double[][] doFloyd() { + int size = InitMatrix.size; + for (int k = 1; k <= size; k++) + for (int i = 1; i <= size; i++) + for (int j = 1; j <= size; j++) + if (matrix[i][j] > matrix[i][k] + matrix[k][j]) + matrix[i][j] = matrix[i][k] + matrix[k][j]; + return matrix; + } +} +``` + +------- + +-**Tarjan**([Back to Index](#AnchorIndex)) +Tarjan算法用于求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边,有向图不再连通。 + +Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。 + +定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。 + + * 对于树枝边(u,v),有low[u]=min(low[u],low[v]). + * 对于后向边(u,v)(指向在当前栈中节点的边),有low[u]=min(low[u],dfn[v]). + +当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。 + +```cpp +#include +using namespace std; +int times=1,low[1000],dfn[1000]; + +int stack[1000],top=0; + +bool instack[1000]={false}; + +struct LIST +{ + int v; + LIST *next; +}; + +LIST *head[1000]={NULL}; + +int min(int a,int b) +{ + if(anext) /*遍历V能直接到达的点*/ + if(!dfn[p->v]) /*如果v的邻接点没有入过栈*/ + { + tarjan(p->v); + low[v]=min(low[v],low[p->v]); /*如果v能直接到达的这个点没在栈中,v的最早祖先为他们中的较小值*/ + } + else if(instack[p->v]) /*如果在栈中*/ + low[v]=min(low[v],dfn[p->v]); /*如果在栈中,则v的最早祖先是他的序号和那个点的序号较小的*/ + + if(dfn[v]==low[v]) /*如果dfn[v]和low[v]相等,则说明v点是其所属强连通分支DFS遍历起点,这个强连通分支说有点都在v点之上*/ + { + cout<<"{ "; + do + { + v=stack[--top]; + instack[v]=false; + cout<>n; + + memset(dfn,0,sizeof(char)*4000); + for(i=1;i<=n;i++) + { + cout<>m; + cout<<"输入每个邻接点编号"; + LIST *rear=head[i]; + for(j=0;jnext=new LIST; + rear=rear->next; + } + rear->next=NULL; + cin>>rear->v; + } + } + + for(i=1;i<=n;i++) + if(!dfn[i]) /*如果i没有入过栈*/ + tarjan(i); + + system("pause"); + return 0; +} ``` \ No newline at end of file diff --git a/Dynamic Programming.md b/Dynamic Programming.md index db499fd..0b75e97 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -6,6 +6,7 @@ Index: -[LeetCode:Interleaving String](#Anchor3) -[LeetCode:Wildcard Matching](#Anchor4) -[LeetCode:Trapping Rain Water](#Anchor5) +-[*TODO*::Leetcode:Palindrome Partitioning II](#Anchor6) ------- @@ -66,6 +67,7 @@ public class Solution { ```cpp class Solution { public: + int numDecodings(string s) { int n = s.size(); if(n <= 0) return 0; @@ -162,10 +164,12 @@ public class Solution { -**[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) **([Back to Index](#AnchorIndex)) -这道题dp[i][j]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] +这道题dp[i][j]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] + ```cpp class Solution { -public: +public: + bool isMatchDp(string& t, string& p){ int tLen = t.length(); int pLen = p.length(); @@ -237,4 +241,9 @@ public: return units; } }; -``` \ No newline at end of file +``` + +------- + +-**[Leetcode:Palindrome Partitioning II](http://oj.leetcode.com/problems/palindrome-partitioning-ii/) **([Back to Index](#AnchorIndex)) + diff --git a/Others.md b/Others.md index eb10c26..dd4cc98 100644 --- a/Others.md +++ b/Others.md @@ -6,6 +6,8 @@ Index: -[Leetcode:Pow(x, n)](#Anchor3) -[Leetcode:Sqrt(x)](#Anchor4) -[*TODO*::Leetcode:Valid Number](#Anchor5) +-[Four Color Theorem](#Anchor6) +-[Count number of digit 1 from 1 to n](#Anchor7) ------- @@ -178,3 +180,79 @@ public: ------- -**[Leetcode:Valid Number](oj.leetcode.com/problems/valid-number/)**([Back to Index](#AnchorIndex)) + +------- + +-**[Four Color Theorem]**([Back to Index](#AnchorIndex)) +四色定理:用颜色去标记图的所有顶点,要求相邻的顶点颜色不同,问最少多少种颜色。 +用数字代表颜色。遍历图,对于每个节点,记录与它相邻节点的颜色,然后选出这些颜色中不包含的、数字最小的颜色,涂在当前节点。 + +```java +public class Solution { + public void FourColor(String[] ss) { + int len = ss.length; + boolean[][] map = new boolean[len + 1][27]; + for (String s : ss) + for (int i = 2; i < s.length(); i++) + map[s.charAt(0) - 'A' + 1][s.charAt(i) - 'A' + 1] = true; + int max = 0; + + int[] color = new int[27]; + for (int i = 1; i <= len; i++) { + boolean[] visit = new boolean[len + 1]; + for (int j = 1; j <= len; j++) + if (map[i][j])//看j是否是i的邻接节点 + if (color[j] != 0)//如果j被涂色了 + visit[color[j]] = true;//将该颜色做标记 + for (int j = 1; j <= len; j++) + if (!visit[j]) {//从中选出序号最小的未被使用的颜色 + color[i] = j;//涂色 + max = Math.max(max, j);//目前用的颜色数量的最大值 + break; + } + } + + System.out.println(max); + } + + public static void main(String[] args) { + Solution m = new Solution(); + // String[] ss = { "A:BCD", "B:ACD", "C:ABD", "D:ABC" }; + String[] ss = { "A:BC", "B:ACD", "C:ABD", "D:BC" }; + m.FourColor(ss); + } +} +``` +------- + +-**[Count number of digit 1 from 1 to n]**([Back to Index](#AnchorIndex)) + +统计从1到n共n个十进制整数中包含1的总数,如输入n=11,统计结果为4(1,10,11)。 +核心思路是按位统计1的个数,以一个例子来说明规则是如何被应用的。统计百位上1的个数: +* 对于十进制数12035,由于百位上的数是'0',故只由百位前面的“高位”决定 + + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) +* 对于十进制数12135,由于百位上的数是'1',故由百位前面的“高位”和百位后面的“低位”共同决定 + + 12 * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199) + + 35 + 1个(12100~12135) +* 对于十进制数12512,由于百位上的数是'5',故由百位前面的“高位”决定 + + (12 + 1) * 100个(0100~0199,1100~1199,2100~2199...10100~10199,11100~11199,12100~12199) +由此可以看出统计规则主要是在统计第x位时,获得x的“高位”和低位,并根据x与1的关系分类计算,代码如下。 + +```cpp +int countOnes(int n){ + int ret = 0, factor = 1; + int higher = 0, cur = 0, lower = 0; + while(n / factor != 0){//n == 12135 + higher = n/(factor*10);//12, when factor == 100 + cur = (n/factor)%10;//1, when factor == 100 + lower = n%factor;//35, when factor == 100 + switch(cur){ + case 0: ret += higher * factor; break; + case 1: ret += higher * factor + lower + 1; break; + default: ret += (higher + 1) * factor; break; + } + factor *= 10; + } + return ret; +} +``` diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index 1445792..884eaba 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -9,6 +9,7 @@ Index: -[Leetcode:Flatten Binary Tree to Linked List](#Anchor6) -[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal](#Anchor7) -[Leetcode:Recover Binary Search Tree](#Anchor8) +-[*TODO*::LeetCode:Binary Tree Maximum Path Sum](#Anchor9) ------- @@ -241,3 +242,7 @@ public: }; ``` +------- + +-**[LeetCode:Binary Tree Maximum Path Sum](http://oj.leetcode.com/problems/binary-tree-maximum-path-sum/)**([Back to Index](#AnchorIndex)) + From 22619a3aacbff8f792932f9d6a02063714319c88 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Wed, 29 Oct 2014 21:33:58 +0800 Subject: [PATCH 304/327] merging --- 11.String$keywords string.md | 236 ----------------------------------- Array & String.md | 138 ++++++++++++++++++++ Dynamic Programming.md | 58 ++++++++- 3 files changed, 195 insertions(+), 237 deletions(-) delete mode 100644 11.String$keywords string.md diff --git a/11.String$keywords string.md b/11.String$keywords string.md deleted file mode 100644 index a65cdd5..0000000 --- a/11.String$keywords string.md +++ /dev/null @@ -1,236 +0,0 @@ -##11.String$keywords string -###*String -尽管已经有了[2.String dp and Array dp](2.String dp and Array dp$keywords dp.md)介绍一些字符串问题的处理方法,但都是基于dp方法。本章收录多种字符串的处理方法。 - -Ex1:[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/) -每次首先判断p当前字符的下一个字符是不是* -* 不是*,如果s和p的当前字符相同,判断s和p的下一位 -* 是*,若p的当前字符是'.',则可以匹配到s的末尾;否则,用p的当前字符一直去匹配s,若p当前字符等于s当前字符,判断若p重复0次s和p是否能匹配;若能则跳出循环,若不能,用p当前字符继续匹配s的下一位。当p的当前字符终于和s的当前字符不相等时,则返回p后面的字符串和s是否匹配 - -```cpp -class Solution { -public: - - bool isMatch(const char *s, const char *p) { - if (*p == '\0') return *s == '\0'; - // next char is not '*', then must match current character - if (*(p + 1) != '*') { - if (*p == *s || (*p == '.' && *s != '\0')) - return isMatch(s + 1, p + 1); - else - return false; - } else { // next char is '*' - while (*p == *s || (*p == '.' && *s != '\0')) { - if (isMatch(s, p + 2)) - return true; - s++; - } - return isMatch(s, p + 2); - } - } -}; -``` - -Ex2:[Leetcode:Simplify Path](http://oj.leetcode.com/problems/simplify-path/) -在每次碰到/之前,都将前面的字符串保存起来;碰到/或者遍历到路径结束,若字符串为'..',表示上一目录;若为'.',表示当前目录;其余情况保存路径,然后重新记录。 -```cpp -class Solution { -public: - - string simplifyPath(string path) { - // Start typing your C/C++ solution below - // DO NOT write int main() function - vector pathes; - string seg = ""; - for (int i = 0; i <= path.size(); ++i) { - if (i == path.size() || path[i] == '/') { - if (seg == "..") { - if (pathes.size() > 0) { - pathes.pop_back(); - } else { - //return "/";//error, in the test set, this case just ignore - } - } else if (seg == ".") { - //do nothing - } else if (seg.size() > 0) { - pathes.push_back(seg); - } - seg = ""; - } else { - seg += path[i]; - } - } - string ret = "/"; - for (int i = 0; i < pathes.size(); ++i) { - if (i > 0) ret += "/"; - ret += pathes[i]; - } - return ret; - } -}; -``` - -Ex3:[Leetcode:Text Justification](http://oj.leetcode.com/problems/text-justification/) -对于每一行都贪婪的加入尽可能多的单词,然后对于多余的空格左对齐插入 -```java -public class Solution { - public static ArrayList fullJustify(String[] words, int L) { - ArrayList ret = new ArrayList(); - int wordsLen = words.length; // 单词数组的长度 - int curWordIdx = 0; // 处理第i个单词 - while(curWordIdx < wordsLen){ // 处理完所有单词后退出 - int charLen = 0; // 当前行累积的字符数量 - int probeWordIdx = curWordIdx; - while(probeWordIdx0){ // 因为居中对齐 - tmp += " "; - leftSpace--; - } - } - tmp += words[probeWordIdx-1]; // 处理当前行的最后一个单词 - if(leftSpace > 0){ // 因为左对齐,所以在最后补上剩下的空格 - tmp = addSpace(tmp, leftSpace); - } - ret.add(tmp); - curWordIdx = probeWordIdx; // 处理下一行的要处理的单词 - } - return ret; - } - - public static String addSpace(String s, int count){ - for(int i=1; i<=count; i++){ - s += " "; - } - return s; - } -} -``` - -Ex4:[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/) -普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。之后长度若能扩展则继续扩展。然后根据i更新最右R。 -```cpp -class Solution { -public: - // Transform S into T. - // For example, S = "abba", T = "^#a#b#b#a#$". - // ^ and $ signs are sentinels appended to each end to avoid bounds checking - - string preProcess(string s) { - int n = s.length(); - if (n == 0) return "^$"; - string ret = "^"; - for (int i = 0; i < n; i++) ret += "#" + s.substr(i, 1); - ret += "#$"; - return ret; - } - - string longestPalindrome(string s) { - string T = preProcess(s); - const int n = T.length(); - // 以T[i] 为中心,向左/右扩张的长度,不包含T[i] 自己, - // 因此P[i] 是源字符串中回文串的长度 - int P[n]; - int C = 0, R = 0; - for (int i = 1; i < n - 1; i++) { - int i_mirror = 2 * C - i; // equals to i' = C - (i-C) - P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; - // Attempt to expand palindrome centered at i - while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) - P[i]++; - // If palindrome centered at i expand past R, - // adjust center based on expanded palindrome. - if (i + P[i] > R) { - C = i; - R = i + P[i]; - } - } - // Find the maximum element in P. - int max_len = 0; - int center_index = 0; - for (int i = 1; i < n - 1; i++) { - if (P[i] > max_len) { - max_len = P[i]; - center_index = i; - } - } - return s.substr((center_index - 1 - max_len) / 2, max_len); - } -}; -``` - -Ex5:KMP算法(Removed) -即字符串匹配问题。首先要算出字符串的覆盖数组,当发生在j长度失配时,只要把pattern向右移动j-overlay(j)长度就可以了。 - -```cpp -#include -#include -#include -using namespace std; - -int kmp_find(const string& target, const string& pattern) { - const int target_length = target.size(); - const int pattern_length = pattern.size(); - int * overlay_value = new int[pattern_length]; - overlay_value[0] = -1; - int index = 0; - for (int i = 1; i < pattern_length; ++i) { - index = overlay_value[i - 1]; - while (index >= 0 && pattern[index + 1] != pattern[i]) { - index = overlay_value[index]; - } - if (pattern[index + 1] == pattern[i]) { - overlay_value[i] = index + 1; - } else { - overlay_value[i] = -1; - } - } - //match algorithm start - int pattern_index = 0; - int target_index = 0; - while (pattern_index < pattern_length && target_index < target_length) { - if (target[target_index] == pattern[pattern_index]) { - ++target_index; - ++pattern_index; - } else if (pattern_index == 0) { - ++target_index; - } else { - pattern_index = overlay_value[pattern_index - 1] + 1; - } - } - if (pattern_index == pattern_length) { - return target_index - pattern_index; - } else { - return -1; - } - delete [] overlay_value; -} - -int main() { - string source = " annbcdanacadsannannabnna"; - string pattern = " annacanna"; - cout << kmp_find(source, pattern) << endl; - return 0; -} - -``` diff --git a/Array & String.md b/Array & String.md index 858831f..eb0ab36 100644 --- a/Array & String.md +++ b/Array & String.md @@ -20,6 +20,9 @@ Index: -[LeetCode:4Sum](#Anchor17) -[LeetCode:Combination Sum](#Anchor18) -[LeetCode:Combination Sum II](#Anchor19) +-[Leetcode:Regular Expression Matching](#Anchor20) +-[Leetcode:Simplify Path](#Anchor21) +-[Leetcode:Text Justification](#Anchor22) ------- @@ -1005,4 +1008,139 @@ public: return; }*/ }; +``` + +------- + +-**[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/)**([Back to Index](#AnchorIndex)) + +每次首先判断p当前字符的下一个字符是不是* +* 不是*,如果s和p的当前字符相同,判断s和p的下一位 +* 是*,若p的当前字符是'.',则可以匹配到s的末尾;否则,用p的当前字符一直去匹配s,若p当前字符等于s当前字符,判断若p重复0次s和p是否能匹配;若能则跳出循环,若不能,用p当前字符继续匹配s的下一位。当p的当前字符终于和s的当前字符不相等时,则返回p后面的字符串和s是否匹配。 + +```cpp +class Solution { +public: + + bool isMatch(const char *s, const char *p) { + if (*p == '\0') return *s == '\0'; + // next char is not '*', then must match current character + if (*(p + 1) != '*') { + if (*p == *s || (*p == '.' && *s != '\0')) + return isMatch(s + 1, p + 1); + else + return false; + } else { // next char is '*' + while (*p == *s || (*p == '.' && *s != '\0')) { + if (isMatch(s, p + 2)) + return true; + s++; + } + return isMatch(s, p + 2); + } + } +}; +``` + +------- + +-**[Leetcode:Simplify Path](http://oj.leetcode.com/problems/simplify-path/) **([Back to Index](#AnchorIndex)) + +在每次碰到/之前,都将前面的字符串保存起来;碰到/或者遍历到路径结束,若字符串为'..',表示上一目录;若为'.',表示当前目录;其余情况保存路径,然后重新记录。 + +```cpp +class Solution { +public: + + string simplifyPath(string path) { + // Start typing your C/C++ solution below + // DO NOT write int main() function + vector pathes; + string seg = ""; + for (int i = 0; i <= path.size(); ++i) { + if (i == path.size() || path[i] == '/') { + if (seg == "..") { + if (pathes.size() > 0) { + pathes.pop_back(); + } else { + //return "/";//error, in the test set, this case just ignore + } + } else if (seg == ".") { + //do nothing + } else if (seg.size() > 0) { + pathes.push_back(seg); + } + seg = ""; + } else { + seg += path[i]; + } + } + string ret = "/"; + for (int i = 0; i < pathes.size(); ++i) { + if (i > 0) ret += "/"; + ret += pathes[i]; + } + return ret; + } +}; +``` + +------- + +-**[Leetcode:Text Justification](http://oj.leetcode.com/problems/text-justification/)**([Back to Index](#AnchorIndex)) + +对于每一行都贪婪的加入尽可能多的单词,然后对于多余的空格左对齐插入 +```java +public class Solution { + public static ArrayList fullJustify(String[] words, int L) { + ArrayList ret = new ArrayList(); + int wordsLen = words.length; // 单词数组的长度 + int curWordIdx = 0; // 处理第i个单词 + while(curWordIdx < wordsLen){ // 处理完所有单词后退出 + int charLen = 0; // 当前行累积的字符数量 + int probeWordIdx = curWordIdx; + while(probeWordIdx0){ // 因为居中对齐 + tmp += " "; + leftSpace--; + } + } + tmp += words[probeWordIdx-1]; // 处理当前行的最后一个单词 + if(leftSpace > 0){ // 因为左对齐,所以在最后补上剩下的空格 + tmp = addSpace(tmp, leftSpace); + } + ret.add(tmp); + curWordIdx = probeWordIdx; // 处理下一行的要处理的单词 + } + return ret; + } + + public static String addSpace(String s, int count){ + for(int i=1; i<=count; i++){ + s += " "; + } + return s; + } +} ``` \ No newline at end of file diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 0b75e97..4710e21 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -7,6 +7,7 @@ Index: -[LeetCode:Wildcard Matching](#Anchor4) -[LeetCode:Trapping Rain Water](#Anchor5) -[*TODO*::Leetcode:Palindrome Partitioning II](#Anchor6) +-[Leetcode:Longest Palindromic Substring](#Anchor6) ------- @@ -245,5 +246,60 @@ public: ------- --**[Leetcode:Palindrome Partitioning II](http://oj.leetcode.com/problems/palindrome-partitioning-ii/) **([Back to Index](#AnchorIndex)) +-**[Leetcode:Palindrome Partitioning II](http://oj.leetcode.com/problems/palindrome-partitioning-ii/)**([Back to Index](#AnchorIndex)) +------- + +-**[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/)**([Back to Index](#AnchorIndex)) + +普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。之后长度若能扩展则继续扩展。然后根据i更新最右R。 + +```cpp +class Solution { +public: + // Transform S into T. + // For example, S = "abba", T = "^#a#b#b#a#$". + // ^ and $ signs are sentinels appended to each end to avoid bounds checking + + string preProcess(string s) { + int n = s.length(); + if (n == 0) return "^$"; + string ret = "^"; + for (int i = 0; i < n; i++) ret += "#" + s.substr(i, 1); + ret += "#$"; + return ret; + } + + string longestPalindrome(string s) { + string T = preProcess(s); + const int n = T.length(); + // 以T[i] 为中心,向左/右扩张的长度,不包含T[i] 自己, + // 因此P[i] 是源字符串中回文串的长度 + int P[n]; + int C = 0, R = 0; + for (int i = 1; i < n - 1; i++) { + int i_mirror = 2 * C - i; // equals to i' = C - (i-C) + P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; + // Attempt to expand palindrome centered at i + while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) + P[i]++; + // If palindrome centered at i expand past R, + // adjust center based on expanded palindrome. + if (i + P[i] > R) { + C = i; + R = i + P[i]; + } + } + // Find the maximum element in P. + int max_len = 0; + int center_index = 0; + for (int i = 1; i < n - 1; i++) { + if (P[i] > max_len) { + max_len = P[i]; + center_index = i; + } + } + return s.substr((center_index - 1 - max_len) / 2, max_len); + } +}; +``` From b48251c9e6e671e6a9351057f417641e19d66574 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Wed, 29 Oct 2014 22:03:35 +0800 Subject: [PATCH 305/327] merging --- 2.String dp and Array dp$keywords dp.md | 535 ------------------------ Dynamic Programming.md | 316 +++++++++++++- 2 files changed, 314 insertions(+), 537 deletions(-) delete mode 100644 2.String dp and Array dp$keywords dp.md diff --git a/2.String dp and Array dp$keywords dp.md b/2.String dp and Array dp$keywords dp.md deleted file mode 100644 index 6fc5e6b..0000000 --- a/2.String dp and Array dp$keywords dp.md +++ /dev/null @@ -1,535 +0,0 @@ -##2.String dp and Array dp$keywords dp -###*String dp -dp有几种用途,其中之一就是标记和剪枝 - -Ex1:[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/) - -该题dp的作用就是标记和剪枝,使用二维dp[i][len]来表示i i+len-1之间是否有继续搜索的必要,即是否可以将i i+len-1之间的串切成回文。标记是在搜索之前判断的,之后就可dfs来搜索。 - -Note by [@sc703bupt](https://github.com/sc703bupt): isPalindrome方法也可以应用dp以避免重复计算,提高速度。具体做法是使用一个二维数组记录s的所有子串的是否是回文串,如dp[i][j]表示s从i到j的子串是否是回文串,求解时以每个字符为中心向两侧探测,注意奇偶情况分别求解。 -```java -public class Solution { - ArrayList> all = new ArrayList>(); - - public ArrayList> partition(String s) { - all.clear(); - int length = s.length(); - boolean[][] seg = new boolean[length][length + 1]; - for (int len = 1; len <= length; len++) { - for (int i = 0; i < length - len + 1; i++) { - String t = s.substring(i, i + len); - if (isPalindrome(t)) { - seg[i][len] = true; - continue; - } - for (int k = 1; k < len; k++) { - if (seg[i][k] && seg[i + k][len - k]) { - seg[i][len] = true; - break; - } - } - } - } - - part(s, seg, 0, 0, new ArrayList()); - return all; - } - - public void part(String s, boolean[][] seg, int start, int depth, - ArrayList list) { - int length = s.length(); - if (depth == length) { - ArrayList listCopy = new ArrayList(list); - all.add(listCopy); - - return; - } - for (int len = 1; len <= length; len++) { - if (seg[start][len]) { - String word = s.substring(start, start + len); - // System.out.println(word); - if (isPalindrome(word)) { - list.add(word); - part(s, seg, start + len, start + len, list); - list.remove(list.size() - 1); - } - } - } - - } - - public boolean isPalindrome(String s) { - for (int i = 0; i < s.length() / 2; i++) - if (s.charAt(i) != s.charAt(s.length() - i - 1)) - return false; - return true; - } -} -``` -isPalindrome的dp解法: -```cpp - void isPalindrome(string str){ - int len = str.length(); - bool isPalindrome[len][len]; - for(int i = 0; i <= len - 1; i++){//init - for(int j = 0; j <= len - 1; j++){ - isPalindrome[i][j] = false; - } - } - for(int i = 0; i <= len - 1; i++){ - for(int j = 0; j <= min(len-1-i,i); j++){ - if(str[i-j]==str[i+j]){ - isPalindrome[i-j][i+j] = true; - }else{ - break; - } - } - if(i+1<=len-1){ - for(int k = 0; k <= min(len-2-i,i); k++){ - if(str[i-k]==str[i+1+k]){ - isPalindrome[i-k][i+1+k] = true; - }else{ - break; - } - } - } - } -``` -dp的作用其二,记录状态。一般记录int状态或boolean状态,当前状态由上一个状态得到,二维dp[i][j]中的i j也不再局限于字符串的数组下标i j,而有可能是从0到某个最大值,或者从0到某个最大和 - -Ex2:[LeetCode:Interleaving String](http://oj.leetcode.com/problems/interleaving-string/)(Removed) - -此题中dp[i][j]表达的意思是s3中的前(i+j)长度串是否为 s1中的前i长度串 与 s2中的前j长度串 混合组成,使用boolean记录。 -若s3的前i+j-1串已经和s1的前i串与s2的前j-1串匹配,此时若s2的第j个字符和s3的第i+j个字符相等,则说明s3的i+j串和s1的i串与s2的j串匹配。s1的i-1加s2的j同理 -```java -public class Solution { - public boolean isInterleave(String s1, String s2, String s3) { - if (s3.length() != s1.length() + s2.length()) - return false; - if (s1.length() == 0) - if (!s2.equals(s3)) - return false; - else - return true; - if (s2.length() == 0) - if (!s1.equals(s3)) - return false; - else - return true; - boolean[][] dp = new boolean[s1.length() + 1][s2.length() + 1]; - dp[0][0] = true; - - for (int i = 1; i <= s1.length(); i++) - if (dp[i - 1][0] && s1.charAt(i - 1) == s3.charAt(i - 1)) - dp[i][0] = true; - - for (int j = 1; j <= s2.length(); j++) - if (dp[0][j - 1] && s2.charAt(j - 1) == s3.charAt(j - 1)) - dp[0][j] = true; - - for (int i = 1; i <= s1.length(); i++) - for (int j = 1; j <= s2.length(); j++) { - if (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) - dp[i][j] = true; - if (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1)) - dp[i][j] = true; - } - - return dp[s1.length()][s2.length()]; - } - - public static void main(String[] args) { - Solution m = new Solution(); - String s1 = "aabccabc"; - String s2 = "dbbabc"; - String s3 = "aabdbbccababcc"; - boolean result = m.isInterleave(s1, s2, s3); - System.out.print(result); - } -} -``` - -Ex3:[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) - -又是一道字符串匹配的题。这道题dp[j][i]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] -```cpp -class Solution { -public: - bool isMatchDp(string& t, string& p){ - int tLen = t.length(); - int pLen = p.length(); - - bool dp[pLen+1][tLen+1]; - memset(dp, 0, sizeof(dp)); - - dp[0][0] = true; - - for(int i = 1; i <= pLen; i++){ - if(dp[i-1][0]&&p[i-1]=='*'){ - dp[i][0] = true; - } - } - - for(int i = 1; i <= pLen; i++){ - for(int j = 1; j <= tLen; j++){ - if((p[i-1] == '?')||p[i-1] == t[j-1]){ - dp[i][j] = dp[i-1][j-1]; - }else if(p[i-1] == '*'){ - dp[i][j] = dp[i-1][j]||dp[i][j-1]; - }else{ - dp[i][j] = false; - } - } - } - - return dp[pLen][tLen]; - } -}; -``` - -附该题的递归解法,时间复杂度高于dp方法,但是一个比较直观的思路。 -```cpp -//recursive -bool isMatch(string& t, string& p, int tPtr, int pPtr){ - if(p.length() == pPtr&&t.length() == tPtr) return true; - if(t.length() == tPtr||p.length() == pPtr) return false; - - if(p[pPtr] == '?'){ - return isMatch(t, p, tPtr+1, pPtr+1); - }else if(p[pPtr] == '*'){ - int tempPtr = tPtr; - while(tempPtr != t.length()+1){ - if(isMatch(t, p, tempPtr, pPtr+1)){ - return true; - } - tempPtr++; - } - return false; - }else if(p[pPtr] == t[tPtr]){ - return isMatch(t, p, tPtr+1, pPtr+1); - }else{ - return false; - } -} -``` - -Ex4:[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/) - -两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 - -Add by[@sc703bupt](https://github.com/sc703bupt): 给出一种“正向”迭代式dp解法,c++代码。 -```java -public class Solution { - public int minDistance(String word1, String word2) { - if (word1.length() == 0) - return word2.length(); - if (word2.length() == 0) - return word1.length(); - int[][] dp = new int[word1.length()][word2.length()]; - int result = search(0, 0, word1, word2, dp); - return result; - } - - public int search(int i, int j, String s1, String s2, int[][] dp) { - if (i == s1.length()) - return s2.length() - j; - if (j == s2.length()) - return s1.length() - i; - if (dp[i][j] != 0) - return dp[i][j]; - if (s1.charAt(i) == s2.charAt(j)) { - int tmp = search(i + 1, j + 1, s1, s2, dp); - dp[i][j] = tmp; - return tmp; - } - int tmp1 = search(i, j + 1, s1, s2, dp) + 1; - int tmp2 = search(i + 1, j, s1, s2, dp) + 1; - int tmp3 = search(i + 1, j + 1, s1, s2, dp) + 1; - int result = tmp1; - if (result > tmp2) - result = tmp2; - if (result > tmp3) - result = tmp3; - dp[i][j] = result; - return result; - } -} -``` -迭代式dp解法: -```cpp -class Solution { -public: - int minDistance(string word1, string word2) { - vector > record; - record.resize(word1.size()+1); - for(int i = 0; i <= word1.size(); i++){ - for(int j = 0; j <= word2.size(); j++){ - record[i].push_back(0); - } - //record.push_back(vector(word2.size()+1)); - record[i][0] = i; - } - for(int j = 0; j <= word2.size(); j++){ - record[0][j] = j; - } - int tempMin = 0, subVal = 0; - for(int i = 1; i <= word1.size(); i++){ - for(int j = 1; j <= word2.size(); j++){ - tempMin = record[i][j-1] + 1;//add - tempMin = tempMin < record[i-1][j] + 1?tempMin:record[i-1][j] + 1;//delete - subVal = ((word1[i-1] == word2[j-1])?0:1);//judge current char word1[i] and word2[j] - tempMin = tempMin < record[i-1][j-1] + subVal?tempMin:record[i-1][j-1] + subVal;//revise - record[i][j] = tempMin; - } - } - return record[word1.size()][word2.size()]; - } -}; -``` -###*Array dp - -Ex5:最长公共子序列(LCS):请编写一个函数,输入两个字符串,求它们的最长公共子序列长度,并打印出最长公共子序列。 - -经典的动态规划问题。dp[i][j]表示p1的前i的个字符和p2的前j个字符匹配的最大长度。定位到dp[i][j]。若p1中的第i个字符与p2的第j个字符相等,则dp[i][j]=dp[i-1][j-1]+1;若不相等,则为dp[i-1][j]和dp[i][j-1]中较大的一个。关键问题是如何打印最长公共子序列。这里我们可以再使用一个二维数组mark来标记当前的状态是从哪一个状态得来。mark[i][j]有三个值,分别为1 2 3,1表示由dp[i-1][j]得来,2表示由dp[i-1][j-1]得来,3表示由dp[i][j-1]得来。当得到最长公共子序列的长度后,dp[p1.length()-1][p2.length()-1]开始向前查找,mark[i][j]为1 i--,为3 j--,为2 i-- j--并将当前值填入结果数组。最后将数组逆序输出即可。 -```java -import java.util.ArrayList; - -public class MyOwn { - public void LCS(char[] a, char[] b) { - int len1 = a.length; - int len2 = b.length; - int[][] dp = new int[len1 + 1][len2 + 1]; - char[][] mark = new char[len1 + 1][len2 + 1]; - - for (int i = 0; i <= len1; i++) - dp[i][0] = 0; - for (int i = 0; i <= len2; i++) - dp[0][i] = 0; - for (int i = 1; i <= len1; i++) - for (int j = 1; j <= len2; j++) { - if (a[i - 1] == b[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - mark[i][j] = '2'; - } else { - if (dp[i][j - 1] >= dp[i - 1][j]) { - dp[i][j] = dp[i][j - 1]; - mark[i][j] = '3'; - } else { - dp[i][j] = dp[i - 1][j]; - mark[i][j] = '1'; - } - } - } - - System.out.println(dp[len1][len2]); - ArrayList l = new ArrayList(); - int i = len1; - int j = len2; - while (i >= 0 && j >= 0) { - if (mark[i][j] == '1') - i--; - - else if (mark[i][j] == '3') - j--; - - else { - l.add(i); - i--; - j--; - } - } - for (i = l.size() - 1; i >= 0; i--) - System.out.print(a[l.get(i)] + " "); - } - - public static void main(String[] args) { - MyOwn m = new MyOwn(); - char[] a = { 'c', 'n', 'b', 'l', 'o', 'g', 's' }; - char[] b = { 'b', 'e', 'l', 'o', 'n', 'g' }; - m.LCS(a, b); - } -} -``` - -Ex6:最长上升子序列(LIS):给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1,s2,s3…sn递增并且这个子序列的长度最长。输出这个最长的长度。 - -又一个经典的动态规划问题。不同的是这次使用的是一维数组,空间复杂度下降了,dp依旧记录状态,只不过记录的状态很特别,dp[i] -=j表示长度为i的递增子序列的最后一个数是j。在对原数组遍历的过程中,每一次都要将a[i]更新到dp的对应位置去。比如a[4]=3,而dp[1]=2,dp[2]=4,表示长度为1的递增子序列最后一个数是2,长度为2的递增子序列最后一个数是4,此时就可以将dp[2]更新为3,因为长度为1的递增子序列最后一位为2,3大于2,所以序列长度加一,最后一位为3,3小于4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 - -Add by[@sc703bupt](https://github.com/sc703bupt): 实际上[@popolou](https://github.com/popolou)的解法是贪心法,使用了一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素大的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4 - -Add by[@sc703bupt](https://github.com/sc703bupt): 等效问题:求解一个数列中需要调整的最少次数使得该数列有序,一次调整操作如将1,2,4,6,5,3变换为1,2,3,4,6,5。 - -```java -import java.util.ArrayList; - -public class MyOwn1 { - public void LIS(int[] a) { - int len = a.length; - int[] b = new int[len + 1]; - b[1] = a[0]; - int max = 1; - ArrayList result = new ArrayList(); - for (int i = 1; i < len; i++) { - int start = 1; - int end = max; - while (start <= end) { - int middle = (start + end) / 2; - if (b[middle] < a[i]) - start = middle + 1; - else if (b[middle] > a[i]) - end = middle - 1; - } - b[start] = a[i]; - if (start > max) { - max++; - result.clear(); - for (int j = 1; j <= max; j++) - result.add(b[j]); - } - } - System.out.println("result: " + max); - System.out.println(result); - } - - public static void main(String[] args) { - MyOwn1 m = new MyOwn1(); - int[] a = { 2, 1, 5, 3, 6, 4, 8, 9, 7 }; - m.LIS(a); - } -} -``` - -Ex7:将数组分成元素个数相等,和最接近的两部分,求和的较大值 - -dp可以有两种状态,boolean和int,这两种方法都可以用来解决这道题。 -首先看int dp。二维dp[i][j]中,i和j不再表示数组下标。dp[i][j]表示取i件物品,总和不超过j的最大值是多少。关注dp[i][j]。遍历到某一件物品k,若状态dp[i-1][j-a[k]]=m(表示可以到达该状态),则dp[i][j]可以为m+a[k],但我们并不能确定dp[i][j]为最大值,因为可能已经通过别的方式到达dp[i][j],所以dp[i][j]=max(dp[i-1][j-a[k]]+a[k],dp[i][j]),表示这第k件物品可加可不加。 -再看boolean dp。dp[i][j]表示是否可以找到i个数,使他们的和等于j。依旧关注dp[i][j]。对于一件物品k,若状态dp[i-1][j-a[k]]可达到,则dp[i][j]可达到。 - -```java - -public class Solution { - int arr[] = { 0, 1, 5, 7, 8, 9, 6, 3, 11, 20, 17 }; - int N = 5; - int SUM = 87; - - int solve2() { - int i, j, s; - int[][] dp = new int[N + 1][SUM / 2 + 2]; - - for (i = 1; i <= 2 * N; ++i) { - // for (j = 1; j <= Math.min(i, N); ++j) { - for (j = 1; j <= N; ++j) { - for (s = SUM / 2 + 1; s >= arr[i]; --s) // 01背包从大到小,可以省空间,即最外层的空间 - { - dp[j][s] = Math.max(dp[j - 1][s - arr[i]] + arr[i], - dp[j][s]); - } - } - } - return dp[N][SUM / 2 + 1]; - } - - int solve3() { - int i, j, s; - int[][] isOK = new int[N + 1][SUM / 2 + 2]; // isOK[i][v]表示是否可以找到i个数,使得它们之和等于v - // 注意初始化 - isOK[0][0] = 1; // 可以,取0件物品,总合为0,是合法的 - - for (i = 1; i <= 2 * N; ++i) { - for (j = 1; j <= Math.min(i, N); ++j) { - for (s = SUM / 2 + 1; s >= arr[i]; --s) // 从大到小,数组少了一维 - { - if (isOK[j - 1][s - arr[i]] == 1) - isOK[j][s] = 1; - } - } - } - for (s = SUM / 2 + 1; s >= 0; --s) { - if (isOK[N][s] == 1) - return s; - } - return 0; - } -} -``` - -Ex8:求随机数构成的数组中最长的等差数列, 输出等差数列由小到大 - -这道题的dp[i][j]就更有点神奇了,dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢?j是等差之差,i是最后一个元素。如果能有a[i]-a[t]=j的话,那么dp[t][j]就应该能达到dp[i][j],并且dp[i][j]有可能等于dp[t][j]+1,因为和之前题目中的原因一样,有可能这个状态在之前已经被遍历过了,有更大的值,所以dp[i][j]=max(dp[t][j]+1,dp[i][j])。又,如果dp[i][j]大于我们记录的等差数列长度的最大值,则更新等差数列长度最大值,同时记录等差数列最后一个元素,等差之差。有了这三个元素就可以推出整个等差数列的元素。 - -```java -public class MyOwn { - public void solve4(int[] a) { - int len = a.length; - int maxv = Integer.MIN_VALUE; - int minv = Integer.MAX_VALUE; - for (int i : a) { - if (i > maxv) - maxv = i; - if (i < minv) - minv = i; - } - int max = maxv - minv; - int[][] dp = new int[len][max + 1]; - for (int i = 0; i < len; i++) - for (int j = 0; j <= max; j++) - dp[i][j] = 1; - int ans = 0; - int end = 0; - int dist = 0; - - for (int i = 1; i < len; i++) - for (int j = 0; j <= i - 1; j++) { - int temp = a[i] - a[j]; - if (temp > 0) { - dp[i][temp] = Math.max(dp[j][temp] + 1, dp[i][temp]); - if (dp[i][temp] > ans) { - ans = dp[i][temp]; - end = i; - dist = temp; - } - } - } - - System.out.println("result: " + ans); - int start = a[end] - (ans - 1) * dist; - for (int i = 0; i < ans; i++) - System.out.print(start + i * dist + " "); - System.out.println(); - } -} -``` - -Ex9:[Leetcode:Distinct Subsequences](http://oj.leetcode.com/problems/distinct-subsequences/) -二维数组dp[T][S],用来记录匹配子序列的个数。 -* dp[0][0] = 1; T和S都是空串 -* dp[0][1 ... S.length() - 1] = 1; T是空串,S只有一种子序列匹配 -* dp[1 ... T.length() - 1][0] = 0; S是空串,T不是空串,S没有子序列匹配 -* dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0).1 <= i <= T.length(), 1 <= j <= S.length() -```cpp -public class Solution { - public int numDistinct(String S, String T) { - // Start typing your Java solution below - // DO NOT write main() function - int[][] dp = new int[T.length() + 1][S.length() + 1]; - dp[0][0] = 1; - for (int i = 1; i <= T.length(); i++) { - dp[i][0] = 0; - } - for (int j = 1; j <= S.length(); j++) { - dp[0][j] = 1; - } - for (int i = 1; i <= T.length(); i++) { - for (int j = 1; j <= S.length(); j++) { - dp[i][j] = dp[i][j - 1]; - if (T.charAt(i - 1) == S.charAt(j - 1)) { - dp[i][j] += dp[i - 1][j - 1]; - } - } - } - return dp[T.length()][S.length()]; - - } -} -``` diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 4710e21..909ea45 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -7,7 +7,13 @@ Index: -[LeetCode:Wildcard Matching](#Anchor4) -[LeetCode:Trapping Rain Water](#Anchor5) -[*TODO*::Leetcode:Palindrome Partitioning II](#Anchor6) --[Leetcode:Longest Palindromic Substring](#Anchor6) +-[*TODO*::Leetcode:Longest Palindromic Substring](#Anchor7) +-[Leetcode:Distinct Subsequences](#Anchor8) +-[LCS](#Anchor9) +-[*TODO*::LIS](#Anchor10) +-[LeetCode:Edit Distance](#Anchor11) +-[*TODO*::LeetCode:Palindrome Partitioning](#Anchor12) +-[Divide Array To Make Two Equal Part](#Anchor13) ------- @@ -163,7 +169,7 @@ public class Solution { ------- --**[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/) **([Back to Index](#AnchorIndex)) +-**[LeetCode:Wildcard Matching](http://oj.leetcode.com/problems/wildcard-matching/)**([Back to Index](#AnchorIndex)) 这道题dp[i][j]表达的意思是s1长度为i的串是否和s2中长度为j的串匹配。但这道题有一个小技巧,就是用s2的字符去匹配s1的字符。当s2的第j个字符是\*时,这里有两种选择:既可以让\*去匹配s1的一个字符,使i前进1,也可以把*当成空白,此时dp[j][i]的状态就等于dp[j-1][i]的状态。当s2遇到?时,和s1的第i个字符与s2的第j个字符相等是等效的,此时dp[j][i]=dp[j-1][i-1] @@ -303,3 +309,309 @@ public: } }; ``` + +------- + +-**[Leetcode:Distinct Subsequences](http://oj.leetcode.com/problems/distinct-subsequences/) **([Back to Index](#AnchorIndex)) + +二维数组dp[T][S],用来记录匹配子序列的个数。 + + * dp[0][0] = 1; T和S都是空串 + * dp[0][1 ... S.length() - 1] = 1; T是空串,S只有一种子序列匹配 + * dp[1 ... T.length() - 1][0] = 0; S是空串,T不是空串,S没有子序列匹配 + * dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0).1 <= i <= T.length(), 1 <= j <= S.length() + +```cpp +public class Solution { + public int numDistinct(String S, String T) { + // Start typing your Java solution below + // DO NOT write main() function + int[][] dp = new int[T.length() + 1][S.length() + 1]; + dp[0][0] = 1; + for (int i = 1; i <= T.length(); i++) { + dp[i][0] = 0; + } + for (int j = 1; j <= S.length(); j++) { + dp[0][j] = 1; + } + for (int i = 1; i <= T.length(); i++) { + for (int j = 1; j <= S.length(); j++) { + dp[i][j] = dp[i][j - 1]; + if (T.charAt(i - 1) == S.charAt(j - 1)) { + dp[i][j] += dp[i - 1][j - 1]; + } + } + } + return dp[T.length()][S.length()]; + + } +} +``` + +------- + +-**[LCS]**([Back to Index](#AnchorIndex)) + +输入两个字符串,求它们的最长公共子序列(LCS)长度,并打印出最长公共子序列。 + +经典的动态规划问题。dp[i][j]表示p1的前i的个字符和p2的前j个字符匹配的最大长度。定位到dp[i][j]。若p1中的第i个字符与p2的第j个字符相等,则dp[i][j]=dp[i-1][j-1]+1;若不相等,则为dp[i-1][j]和dp[i][j-1]中较大的一个。关键问题是如何打印最长公共子序列。这里我们可以再使用一个二维数组mark来标记当前的状态是从哪一个状态得来。mark[i][j]有三个值,分别为1 2 3,1表示由dp[i-1][j]得来,2表示由dp[i-1][j-1]得来,3表示由dp[i][j-1]得来。当得到最长公共子序列的长度后,dp[p1.length()-1][p2.length()-1]开始向前查找,mark[i][j]为1 i--,为3 j--,为2 i-- j--并将当前值填入结果数组。最后将数组逆序输出即可。 + +```java +import java.util.ArrayList; + +public class MyOwn { + public void LCS(char[] a, char[] b) { + int len1 = a.length; + int len2 = b.length; + int[][] dp = new int[len1 + 1][len2 + 1]; + char[][] mark = new char[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) + dp[i][0] = 0; + for (int i = 0; i <= len2; i++) + dp[0][i] = 0; + for (int i = 1; i <= len1; i++) + for (int j = 1; j <= len2; j++) { + if (a[i - 1] == b[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + mark[i][j] = '2'; + } else { + if (dp[i][j - 1] >= dp[i - 1][j]) { + dp[i][j] = dp[i][j - 1]; + mark[i][j] = '3'; + } else { + dp[i][j] = dp[i - 1][j]; + mark[i][j] = '1'; + } + } + } + + System.out.println(dp[len1][len2]); + ArrayList l = new ArrayList(); + int i = len1; + int j = len2; + while (i >= 0 && j >= 0) { + if (mark[i][j] == '1') + i--; + + else if (mark[i][j] == '3') + j--; + + else { + l.add(i); + i--; + j--; + } + } + for (i = l.size() - 1; i >= 0; i--) + System.out.print(a[l.get(i)] + " "); + } + + public static void main(String[] args) { + MyOwn m = new MyOwn(); + char[] a = { 'c', 'n', 'b', 'l', 'o', 'g', 's' }; + char[] b = { 'b', 'e', 'l', 'o', 'n', 'g' }; + m.LCS(a, b); + } +} +``` + +------- + +-**[LIS]**([Back to Index](#AnchorIndex)) +最长上升子序列(LIS),给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1,s2,s3…sn递增并且这个子序列的长度最长。输出这个最长的长度。 + +又一个经典的动态规划问题。不同的是这次使用的是一维数组,空间复杂度下降了,dp依旧记录状态,只不过记录的状态很特别,dp[i] +=j表示长度为i的递增子序列的最后一个数是j。在对原数组遍历的过程中,每一次都要将a[i]更新到dp的对应位置去。比如a[4]=3,而dp[1]=2,dp[2]=4,表示长度为1的递增子序列最后一个数是2,长度为2的递增子序列最后一个数是4,此时就可以将dp[2]更新为3,因为长度为1的递增子序列最后一位为2,3大于2,所以序列长度加一,最后一位为3,3小于4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 + +Add by[@sc703bupt](https://github.com/sc703bupt): 实际上[@popolou](https://github.com/popolou)的解法是贪心法,使用了一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素大的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4 + +Add by[@sc703bupt](https://github.com/sc703bupt): 等效问题:求解一个数列中需要调整的最少次数使得该数列有序,一次调整操作如将1,2,4,6,5,3变换为1,2,3,4,6,5。 + +```java +import java.util.ArrayList; + +public class MyOwn1 { + public void LIS(int[] a) { + int len = a.length; + int[] b = new int[len + 1]; + b[1] = a[0]; + int max = 1; + ArrayList result = new ArrayList(); + for (int i = 1; i < len; i++) { + int start = 1; + int end = max; + while (start <= end) { + int middle = (start + end) / 2; + if (b[middle] < a[i]) + start = middle + 1; + else if (b[middle] > a[i]) + end = middle - 1; + } + b[start] = a[i]; + if (start > max) { + max++; + result.clear(); + for (int j = 1; j <= max; j++) + result.add(b[j]); + } + } + System.out.println("result: " + max); + System.out.println(result); + } + + public static void main(String[] args) { + MyOwn1 m = new MyOwn1(); + int[] a = { 2, 1, 5, 3, 6, 4, 8, 9, 7 }; + m.LIS(a); + } +} +``` + +------- + +-**[LeetCode:Edit Distance](http://oj.leetcode.com/problems/edit-distance/)**([Back to Index](#AnchorIndex)) + +求两个字符串的最小距离。在本题中,dp同时起到了标记和记录状态的作用,表示s1中前面长度为i的串和s2中前面长度为j的串匹配的最小距离。用过dfs的同学都知道,一般dfs是当遍历到末尾才开始返回值的,本题dfs的目的就是返回dp[i][j]的最小值。既然返回的是最小值,所以对于每一个dp[i][j]来说,只要遍历过一遍就够了,第一次遍历赋值,第二次遍历到dp[i][j]直接返回dp[i][j]的值。然后关注当前状态dp[i][j]。若s1中第i个字符和s2中第j个字符相等,dp[i][j]=dp[i-1][j-1],自然不用说;若不相等,则分成了增删改三种情况:增的话j+1,相当于在s1中加了一个字符与s2中第j个字符匹配;删,i+1,s1第i个字符被删掉,用s1第i+1个与s2第j个字符匹配;改,改后s1第i个字符等于s2第j个字符,i+1,j+1。以上三种情况匹配距离都要加一。然后取出三者中小的赋给dp[i][j]。 + +```cpp +class Solution { +public: + int minDistance(string word1, string word2) { + vector > record; + record.resize(word1.size()+1); + for(int i = 0; i <= word1.size(); i++){ + for(int j = 0; j <= word2.size(); j++){ + record[i].push_back(0); + } + //record.push_back(vector(word2.size()+1)); + record[i][0] = i; + } + for(int j = 0; j <= word2.size(); j++){ + record[0][j] = j; + } + int tempMin = 0, subVal = 0; + for(int i = 1; i <= word1.size(); i++){ + for(int j = 1; j <= word2.size(); j++){ + tempMin = record[i][j-1] + 1;//add + tempMin = tempMin < record[i-1][j] + 1?tempMin:record[i-1][j] + 1;//delete + subVal = ((word1[i-1] == word2[j-1])?0:1);//judge current char word1[i] and word2[j] + tempMin = tempMin < record[i-1][j-1] + subVal?tempMin:record[i-1][j-1] + subVal;//revise + record[i][j] = tempMin; + } + } + return record[word1.size()][word2.size()]; + } +}; +``` + +------- + +-**[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/)([Back to Index](#AnchorIndex)) + +------- + +-**[Divide Array To Make Two Equal Part]([Back to Index](#AnchorIndex)) +将数组分成元素个数相等,和最接近的两部分,求和的较大值 + +dp可以有两种状态,boolean和int,这两种方法都可以用来解决这道题。 +首先看int dp。二维dp[i][j]中,i和j不再表示数组下标。dp[i][j]表示取i件物品,总和不超过j的最大值是多少。关注dp[i][j]。遍历到某一件物品k,若状态dp[i-1][j-a[k]]=m(表示可以到达该状态),则dp[i][j]可以为m+a[k],但我们并不能确定dp[i][j]为最大值,因为可能已经通过别的方式到达dp[i][j],所以dp[i][j]=max(dp[i-1][j-a[k]]+a[k],dp[i][j]),表示这第k件物品可加可不加。 +再看boolean dp。dp[i][j]表示是否可以找到i个数,使他们的和等于j。依旧关注dp[i][j]。对于一件物品k,若状态dp[i-1][j-a[k]]可达到,则dp[i][j]可达到。 + +```java + +public class Solution { + int arr[] = { 0, 1, 5, 7, 8, 9, 6, 3, 11, 20, 17 }; + int N = 5; + int SUM = 87; + + int solve2() { + int i, j, s; + int[][] dp = new int[N + 1][SUM / 2 + 2]; + + for (i = 1; i <= 2 * N; ++i) { + // for (j = 1; j <= Math.min(i, N); ++j) { + for (j = 1; j <= N; ++j) { + for (s = SUM / 2 + 1; s >= arr[i]; --s) // 01背包从大到小,可以省空间,即最外层的空间 + { + dp[j][s] = Math.max(dp[j - 1][s - arr[i]] + arr[i], + dp[j][s]); + } + } + } + return dp[N][SUM / 2 + 1]; + } + + int solve3() { + int i, j, s; + int[][] isOK = new int[N + 1][SUM / 2 + 2]; // isOK[i][v]表示是否可以找到i个数,使得它们之和等于v + // 注意初始化 + isOK[0][0] = 1; // 可以,取0件物品,总合为0,是合法的 + + for (i = 1; i <= 2 * N; ++i) { + for (j = 1; j <= Math.min(i, N); ++j) { + for (s = SUM / 2 + 1; s >= arr[i]; --s) // 从大到小,数组少了一维 + { + if (isOK[j - 1][s - arr[i]] == 1) + isOK[j][s] = 1; + } + } + } + for (s = SUM / 2 + 1; s >= 0; --s) { + if (isOK[N][s] == 1) + return s; + } + return 0; + } +} +``` + +------- + +-**[Find Longest Arithmetic Progression]([Back to Index](#AnchorIndex)) +求随机数构成的数组中最长的等差数列, 输出等差数列由小到大 + +dp[i][j]表示以数组中第i个元素结尾,等差之差为j的等差数列的长度。由此可以看出在选择dp的i和j时是非常有讲究的。最好放入你认为关系重要的变量,并且dp[i][j]=k中只用i j k三个变量就可以完整的描述各种变化。接下来依旧关注dp[i][j]。什么状态能够达到dp[i][j]呢?j是等差之差,i是最后一个元素。如果能有a[i]-a[t]=j的话,那么dp[t][j]就应该能达到dp[i][j],并且dp[i][j]有可能等于dp[t][j]+1,因为和之前题目中的原因一样,有可能这个状态在之前已经被遍历过了,有更大的值,所以dp[i][j]=max(dp[t][j]+1,dp[i][j])。又,如果dp[i][j]大于我们记录的等差数列长度的最大值,则更新等差数列长度最大值,同时记录等差数列最后一个元素,等差之差。有了这三个元素就可以推出整个等差数列的元素。 + +```java +public class MyOwn { + public void solve4(int[] a) { + int len = a.length; + int maxv = Integer.MIN_VALUE; + int minv = Integer.MAX_VALUE; + for (int i : a) { + if (i > maxv) + maxv = i; + if (i < minv) + minv = i; + } + int max = maxv - minv; + int[][] dp = new int[len][max + 1]; + for (int i = 0; i < len; i++) + for (int j = 0; j <= max; j++) + dp[i][j] = 1; + int ans = 0; + int end = 0; + int dist = 0; + + for (int i = 1; i < len; i++) + for (int j = 0; j <= i - 1; j++) { + int temp = a[i] - a[j]; + if (temp > 0) { + dp[i][temp] = Math.max(dp[j][temp] + 1, dp[i][temp]); + if (dp[i][temp] > ans) { + ans = dp[i][temp]; + end = i; + dist = temp; + } + } + } + + System.out.println("result: " + ans); + int start = a[end] - (ans - 1) * dist; + for (int i = 0; i < ans; i++) + System.out.print(start + i * dist + " "); + System.out.println(); + } +} +``` \ No newline at end of file From 41c1c14b146a69d9a3f8f3086e685285e84cdfc0 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Wed, 29 Oct 2014 22:06:06 +0800 Subject: [PATCH 306/327] revise readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58b9921..9e9b82f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -AlgorithmNote(Our github blog is about to refactor recently) +AlgorithmNote ============= Introduction ------------ From 4d36f6c8ace3d74e5b480a251ca5470adefbc67f Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Thu, 30 Oct 2014 09:50:01 +0800 Subject: [PATCH 307/327] fix #2 --- Others.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Others.md b/Others.md index dd4cc98..0e20b0c 100644 --- a/Others.md +++ b/Others.md @@ -137,8 +137,14 @@ public: } else { - n = -n; - double half = pow(x, n/2); + int halfN = 0; + if(n == INT_MIN){ + long long newN = INT_MAX + 1; + newN = newN / 2; + }else{ + halfN = (-n) / 2; + } + double half = pow(x, halfN); if(n%2 == 0) return 1.0/(half*half); else return 1.0/(half*half*x); } From d13a067b7631c575f9e48233a28779adb9d8ecc0 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Thu, 30 Oct 2014 10:49:37 +0800 Subject: [PATCH 308/327] update Array & String.md --- Array & String.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Array & String.md b/Array & String.md index eb0ab36..4956bcf 100644 --- a/Array & String.md +++ b/Array & String.md @@ -1015,8 +1015,9 @@ public: -**[Leetcode:Regular Expression Matching](http://oj.leetcode.com/problems/regular-expression-matching/)**([Back to Index](#AnchorIndex)) 每次首先判断p当前字符的下一个字符是不是* -* 不是*,如果s和p的当前字符相同,判断s和p的下一位 -* 是*,若p的当前字符是'.',则可以匹配到s的末尾;否则,用p的当前字符一直去匹配s,若p当前字符等于s当前字符,判断若p重复0次s和p是否能匹配;若能则跳出循环,若不能,用p当前字符继续匹配s的下一位。当p的当前字符终于和s的当前字符不相等时,则返回p后面的字符串和s是否匹配。 + + * 不是*,如果s和p的当前字符相同,判断s和p的下一位 + * 是*,若p的当前字符是'.',则可以匹配到s的末尾;否则,用p的当前字符一直去匹配s,若p当前字符等于s当前字符,判断若p重复0次s和p是否能匹配;若能则跳出循环,若不能,用p当前字符继续匹配s的下一位。当p的当前字符终于和s的当前字符不相等时,则返回p后面的字符串和s是否匹配。 ```cpp class Solution { From f96395181569c30fd9165845c47a8c932912631f Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 11 Nov 2014 12:01:15 +0800 Subject: [PATCH 309/327] fix #11 --- Geometry.md | 59 +++++++++++++++++++++++++++ Image/Overlapped Rectangles Area.jpg | Bin 0 -> 28228 bytes 2 files changed, 59 insertions(+) create mode 100644 Image/Overlapped Rectangles Area.jpg diff --git a/Geometry.md b/Geometry.md index ca85b03..2b16be5 100644 --- a/Geometry.md +++ b/Geometry.md @@ -196,3 +196,62 @@ int main(){ -**[Overlapped Rectangles Area]**([Back to Index](#AnchorIndex)) +在二维平面中存在若干个矩形,这些矩形可能有交叠,给定每个矩形的右上角及左下角坐标,求这些矩形的总面积(交叠部分只计算一次)。 + +可以利用切割的思想进行,如下图所示: +![Overlapped Rectangles Area](Image/Overlapped Rectangles Area.png "Overlapped Rectangles Area") + +首先分别获得这些矩形的坐标集合setx和sety,从而确定了分割的基准线。接下来对setx和sety中的值进行排序,这样做的目的是在接下来的算法中对于x和y每次能够选择相邻的基准线,从而获得最小的矩形。对小矩形进行判断,看是否在输入给定的任意一个矩形中,如果在,则其面积应该计算在最后的总和中;如果不在任意一个矩形中,则抛弃该矩形。 + +算法实现如下: +```cpp +class Rect{ + public: + int x1,y1,x2,y2; + Rect(int _x1, int _y1, int _x2, int _y2):x1(_x1),y1(_y1),x2(_x2),y2(_y2){} + ~Rect(); +} + +int CalculateTotalArea(Vector inputRects){ + int n = inputRects.size(); + if(n <= 0) return 0; + set setx, sety; + // collect setx and sety + for(int i = 0; i <= n-1; i++){ + setx.insert(inputRects[i].x1); + setx.insert(inputRects[i].x2); + sety.insert(inputRects[i].y1); + sety.insert(inputRects[i].y2); + } + vector vecx,vecy; + for(set::iterator itr = setx.begin(); itr != setx.end(); itr++){ + vecx.push_back(*itr); + } + sort(vecx.begin(),vecx.end()); + for(set::iterator itr = sety.begin(); itr != sety.end(); itr++){ + vecy.push_back(*itr); + } + sort(vecy.begin(),vecy.end()); + + int totalArea = 0; + for(int i = 0; i <= vecx.size()-2; i++){ + for(int j = 0; j <= vecy.size()-2; j++){ + Rect smallRect(vecx[i],vecy[j],vecx[i+1],vecy[j+1]); + if(judgeSmallRect(inputRects, smallRect)){ + totalArea += (vecx[i+1] - vecx[i]) * (vecy[j+1] - vecy[j]); + } + } + } + + return totalArea; +} + +bool judgeSmallRect(vector inputRects, Rect smallRect){ + for(int i = 0; i <= (int)inputRects.size()-1; i++){ + if(smallRect.x1 <= inputRects[i].x1 && smallRect.x1 >= inputRects[i].x2 && smallRect.x2 <= inputRects[i].x1 && smallRect.x2 >= inputRects[i].x1 && smallRect.y1 <= inputRects[i].y1 && smallRect.y1 >= inputRects[i].y2 && smallRect.y2 <= inputRects[i].y1 && smallRect.y2 >= inputRects[i].y2){ + return true; + } + } + return false; +} +``` \ No newline at end of file diff --git a/Image/Overlapped Rectangles Area.jpg b/Image/Overlapped Rectangles Area.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca2dda9fc179e6cfbdc4202a8ee9f79b02641724 GIT binary patch literal 28228 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χgIDIw|GfZikF$QborY!0sWe!D$9O5 z)F%jn%!2+mon+e{b=6g4g`&gNFlV}6_vgZV0ltgV#Mw@9h z#-%os$BI#z&h)aZ2oId#)k#JDTvDguC@NgqrBG;p`6b`@47{3E^{=Ha(>)UTMOOA1 zj+KZ9${sn_?|UpJRTep$wBGnclCpB5Gsu*od~d6g_x{nAj#)m&wMiYWW@gP6dB-1z zIvx4k6IzH{Go^`OD8yR$S~QIyv6@FrMBC7i(^w{&A&>~Qq>0$FU8lCV7+01VRl&k_ zN`KJDuBDYY(HP^-qeXKO4#bwi?QN$2moHzGTQV%&>!z*BF5J#vQX4`+kKm1()vWA` zqO9yQgY7dXZJORqG;OIsq)Cvp`%2Phq}$JV@1>X@PYIk#@sX}kk}fZK+F*I4!3BeG z@qQ(~<29?^=CRXgP|(Hkh0$4^gD5%szzSbfhU*QC{8e{KPo9E;V5a-sew)L46E*a{ z`|nO*yeRrIP-Ox3Dp@jjjnfqMH#>9OJ}gH`tJj-)p{$@dKHHV1thFF}JtHG4Dh(PT z<5INOyzc4b39agni?mXCm~TAUHg(LFl`w`v^)Rz4RU41Y#OQ|>-1$v0o2`iHdlfs1 zW13-n;apcplNmY$Fc4qW{|fjC0I}kO>{w{FD1cWU!~+=NVibf|61HR81o;qG@~0)E zis1_}Dx{h8M4pIOpz$)(x#$VUVj==5=o(}SkT!#aD=Z^MplR!yul*F*Fg4YW9DC$_ zoG0L;UeomPm*~i^5=$w*O>;+G)0tGIeGQOCcQ?*#r-?$XNpH(9RTs9i)=moT@x!y7 zw!&H$uQ(pdu5CAQ5KClAgtm4Bu=Y74*B`cq@?zo&Uja$)NNyqGapo+%LUNgR(0n|myL1w`|CLNe)@M_`PWT)C2?b#$W7av z<6gLejduL)yg(W{l4V)J31x*li8P=rIqoD}U;}MajS4wGvQ+?a zp%=VlQRtbp@7Nl>R4);ibt#t_7i=}!DI~%dU!X#6a_)6#Zd)e5K_%%vt(ADb66sJN zaeC-{ScS}K?xi?Xd7n+wf`lE+%dMm|hCY!aTUq(Zo@@wgx`K$kL%P>frk)ed1Y6Gb zJA~E;oX@mE$T9s`!k8<_dq8!xhCd^chM@ojxl-rew4a#2;6WQ~?pAHLq#}2s{JJ|8 z>G*i4piekGld97lq~SDjLqlP==evN}qa%$td9S$@&A z039#gonKWcPcPkTzQ3$spSX`I#jH`S$H^nBwbD{`rWS>(nJS1plPWlVy}-c?2HbtmBxtes4af}-|8 z2OGwB?3ThoThdNAExg)&+W%DNS8mm|4^~)71?I$EBS0(; zdSHHFN#ivMO~cdEA1-vt#~4e5(&KK;_6R9tkEg761Q?Y`K9kMHad%%jWQ&bh*De^D zaM|%*e8*>G?J_4HyAF_!%Pv1L|HK{kWtSet1}9k;%oZI6mIeen{Cpn%L)s6JTLl1n zf5l=yq-;`VQUX7%n^h8Y0%fGO_)<{pxs5%YqLtB?+d3* zy~8w~L=(M%dzE+xAv%NHIVPSN43Alws?Ww;jWJD(EnVxZ;ij6h0hx$ANXbb9KxlAwf z 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 Date: Tue, 11 Nov 2014 15:29:11 +0800 Subject: [PATCH 310/327] fix picture issue in Geometry.md --- Geometry.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Geometry.md b/Geometry.md index 2b16be5..e6f5f3d 100644 --- a/Geometry.md +++ b/Geometry.md @@ -198,8 +198,8 @@ int main(){ 在二维平面中存在若干个矩形,这些矩形可能有交叠,给定每个矩形的右上角及左下角坐标,求这些矩形的总面积(交叠部分只计算一次)。 -可以利用切割的思想进行,如下图所示: -![Overlapped Rectangles Area](Image/Overlapped Rectangles Area.png "Overlapped Rectangles Area") +可以利用切割的思想进行,如下图所示: +![Overlapped Rectangles Area](Image/Overlapped Rectangles Area.jpg "Overlapped Rectangles Area") 首先分别获得这些矩形的坐标集合setx和sety,从而确定了分割的基准线。接下来对setx和sety中的值进行排序,这样做的目的是在接下来的算法中对于x和y每次能够选择相邻的基准线,从而获得最小的矩形。对小矩形进行判断,看是否在输入给定的任意一个矩形中,如果在,则其面积应该计算在最后的总和中;如果不在任意一个矩形中,则抛弃该矩形。 From b5bfa17ed4f7217a229af17b4ff05de062c927b0 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Thu, 13 Nov 2014 23:19:40 +0800 Subject: [PATCH 311/327] Done. fix #14 --- Geometry.md | 2 +- Tree & Linkedlist.md | 55 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/Geometry.md b/Geometry.md index e6f5f3d..6ef428d 100644 --- a/Geometry.md +++ b/Geometry.md @@ -3,7 +3,7 @@ Index: -[Leetcode:Max Points on a Line](#Anchor1) -[Outer Points of Rectangles](#Anchor2) --[*TODO*::Overlapped Rectangles Area](#Anchor3) +-[Overlapped Rectangles Area](#Anchor3) ------- diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index 884eaba..ffeee69 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -1,7 +1,7 @@ ##Tree & Linkedlist Index: --[*TODO*::Delete one node from BST](#Anchor1) +-[Delete one node from BST](#Anchor1) -[Transfer BST to sorted double linked list](#Anchor2) -[LCA](#Anchor3) -[*TODO*::Judge two tree are the same under swap operation](#Anchor4) @@ -14,7 +14,60 @@ Index: ------- -**[Delete one node from BST]**([Back to Index](#AnchorIndex)) +从一个二叉搜索树中删除一个指定节点,但要求删除后的二叉搜索树继续保持其性质。 +BST有个重要的性质是其中序遍历的结果为升序序列,因此考虑寻找目标删除节点在中序遍历中的上一个节点或下一个节点,将二者值交换来达到删除的目的。假设TreeNode中有指向父节点的指针。 + +```cpp +void deleteTreeNode(TreeNode * target){ + // NULL tree need not delete + if(target == NULL){ + return; + } + // find previous node in the left sub-tree + if(target->left != NULL){ + TreeNode * preNode = target->left; + while(preNode->right != NULL){ + preNode = preNode->right; + } + target->val = preNode->val; + // no matter preNode->left is NULL or not, hang it to its parent + if(preNode->parent->right == preNode){ + preNode->parent->right = preNode->left; + }else{ + preNode->parent->left = preNode->left; + } + delete preNode; + }else if(target->right != NULL){// find next node in the right sub-tree + TreeNode * nextNode = target->right; + while(nextNode->left != NULL){ + nextNode = nextNode->left; + } + target->val = nextNode->val; + + if(nextNode->parent->left == nextNode){ + nextNode->parent->left = nextNode->right; + }else{ + nextNode->parent->right = nextNode->right; + } + delete nextNode; + }else{// it's a leaf itself + if(target->parent == NULL){ + delete target; + }else{ + TreeNode * parent = target->parent; + if(target->parent->left == target){ + parent->left = NULL; + delete target; + }else{ + parent->right = NULL; + delete target; + } + } + } +} + +``` ------- From f4b7a60c58e012697b9b3ffaf34b168e9adbcacb Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 14 Nov 2014 13:28:17 +0800 Subject: [PATCH 312/327] Done. fix #12 --- Others.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/Others.md b/Others.md index 0e20b0c..33fa049 100644 --- a/Others.md +++ b/Others.md @@ -5,7 +5,7 @@ Index: -[Leetcode:Gray Code](#Anchor2) -[Leetcode:Pow(x, n)](#Anchor3) -[Leetcode:Sqrt(x)](#Anchor4) --[*TODO*::Leetcode:Valid Number](#Anchor5) +-[Leetcode:Valid Number](#Anchor5) -[Four Color Theorem](#Anchor6) -[Count number of digit 1 from 1 to n](#Anchor7) @@ -187,6 +187,55 @@ public: -**[Leetcode:Valid Number](oj.leetcode.com/problems/valid-number/)**([Back to Index](#AnchorIndex)) +判断一个字符串是否为合法的数,包括带科学计数法的整数,小数等。思路是使用几个状态变量来表示目前已处理的部分的状态,当状态出现矛盾或违规时返回错误即可,包括:空格已出现isSpace,第一部分出现isFirst,第二部分(以E/e作为分割)出现isSecond, +E/e出现isE, 小数点出现isDot。控制好这5个变量即可。 + +```cpp +bool isNumber(const char* s){ + if(s == NULL) return false; + while(*s == ' ') s++; + if(*s == '+' || *s == '-') s++; + bool isSpace = false, isFirst = false, isSecond = false, isE = false, isDot = false; + while(*s != '\0'){ + if(*s == '.'){ + if(isSpace || isE || isDot){ + return false; + }else{ + isDot = true; + } + }else if(*s == 'E' || *s == 'e'){ + if(isSpace || isE || !isFirst){ + return false; + }else{ + isE = true; + } + }else if(*s == ' '){ + isSpace = true; + }else if(*s == '+' || *s == '-'){ + is(isSpace) return false; + if(*(s-1) != 'E' || *(s-1) != 'e') return false; + }else if(*s <= '9' && *s >= '0'){ + if(isSpace) return false; + if(isE){ + isSecond = true; + }else{ + isFirst = true; + } + }else{ + return false; + } + s++; + } + + if(!FirstPart){ + return false; + }else if(isE && !isSecond){ + return false; + }else{ + return true; + } +} +``` ------- -**[Four Color Theorem]**([Back to Index](#AnchorIndex)) From 5e7c01f876efff775186cb2da59109f6cf0b98d4 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 14 Nov 2014 13:32:25 +0800 Subject: [PATCH 313/327] Add TODO in Tree&Likedlist chapter --- Tree & Linkedlist.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index ffeee69..e7bec4d 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -10,6 +10,7 @@ Index: -[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal](#Anchor7) -[Leetcode:Recover Binary Search Tree](#Anchor8) -[*TODO*::LeetCode:Binary Tree Maximum Path Sum](#Anchor9) +-[*TODO*::Judge one tree is BST under swap operation](#Anchor10) ------- @@ -299,3 +300,6 @@ public: -**[LeetCode:Binary Tree Maximum Path Sum](http://oj.leetcode.com/problems/binary-tree-maximum-path-sum/)**([Back to Index](#AnchorIndex)) +------- + +-**[Judge one tree is BST under swap operation]**([Back to Index](#AnchorIndex)) \ No newline at end of file From 26cf10f7f1d3d206b3a59601a328441d47ba5c32 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 14 Nov 2014 17:49:27 +0800 Subject: [PATCH 314/327] Done. fix #13 --- Tree & Linkedlist.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index e7bec4d..04db6d7 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -4,7 +4,7 @@ Index: -[Delete one node from BST](#Anchor1) -[Transfer BST to sorted double linked list](#Anchor2) -[LCA](#Anchor3) --[*TODO*::Judge two tree are the same under swap operation](#Anchor4) +-[Judge two tree are the same under swap operation](#Anchor4) -[Leetcode:Binary Tree Zigzag Level Order Traversal](#Anchor5) -[Leetcode:Flatten Binary Tree to Linked List](#Anchor6) -[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal](#Anchor7) @@ -137,6 +137,25 @@ TreeNode* getLCA(TreeNode* root, TreeNode* X, TreeNode *Y) { -**[Judge two tree are the same under swap operation]**([Back to Index](#AnchorIndex)) +定义一种交换操作,可以任意交换树中某节点的左右子树。现给定两棵树,求解是否存在某种交换方法,使得两棵树相同。 + +用递归的思想解决这个问题,假设给定一个方法能够判断分别来自两棵树的子树能够通过交换操作变形为相同,则要么两棵子的左左和右右子树对应相同(在进行交换操作的前提下),要么两棵子树的左右,右左子树对应相同(同样在进行交换操作的前提下),这样就把问题转换为更小的子问题。递归出口是当两棵树为空树时,定义这两棵树能够通过交换变为相同。 + +```cpp +bool canSwapToSame(TreeNode * r1, TreeNode * r2){ + if(r1 == NULL && r2 == NULL) return true; + if(r1 == NULL || r2 == NULL) return false; + if(r1->val != r2->val) return false; + if(canSwapToSame(r1->left,r2->left)&&canSwapToSame(r1->right,r2->right)){ + return true; + } + if(canSwapToSame(r1->left,r2->right)&&canSwapToSame(r1->right,r2->left)){ + return true; + } + return false; +} +``` + ------- -**[Leetcode:Binary Tree Zigzag Level Order Traversal](http://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/)**([Back to Index](#AnchorIndex)) From 6d14f1fa9dc828e96dc6f6978d78708ee428ab68 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 14 Nov 2014 18:35:27 +0800 Subject: [PATCH 315/327] Done. fix #16 --- Tree & Linkedlist.md | 64 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index 04db6d7..37fb700 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -10,7 +10,7 @@ Index: -[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal](#Anchor7) -[Leetcode:Recover Binary Search Tree](#Anchor8) -[*TODO*::LeetCode:Binary Tree Maximum Path Sum](#Anchor9) --[*TODO*::Judge one tree is BST under swap operation](#Anchor10) +-[Judge one tree is BST under swap operation](#Anchor10) ------- @@ -321,4 +321,64 @@ public: ------- --**[Judge one tree is BST under swap operation]**([Back to Index](#AnchorIndex)) \ No newline at end of file +-**[Judge one tree is BST under swap operation]**([Back to Index](#AnchorIndex)) +这里定义的交换操作与[Judge two tree are the same under swap operation](#Anchor4)定义的相同。给定一棵树,每个节点存有一个整数,判断这棵树是否能够通过某种交换操作序列变换为BST。 + +考虑BST的性质:对于某个节点来说,其左子树为BST且其所有节点的值都小于该节点值,其右子树为BST且所有节点的值都大于该节点值。将这个性质与交换操作结合起来即为解题思路。在判断左右子树是否能通过交换操作变换为BST的同时,使用传引用返回左子树和右子树的最大最小值,判断交换和不交换两种情况下能否使得以当前节点为根的子树BST性质成立即可,如果两种情况都无法满足BST性质,则返回false。递归出口是对于空节点进行特判,并在后续的调用过程中不对空节点进行递归(简便起见,可以有别的实现方式)。 + +```cpp +bool canSwapToBST(TreeNode * root, int & maxVal, int & minVal){ + if(root == NULL){ + return false; + } + int leftMin,leftMax,rightMin,rightMax; + bool isLeftValid, isRightValid; + if(root->left != NULL){ + isLeftValid = true; + if(!canSwapToBST(root->left, leftMax, leftMin)){ + return false; + } + }else{ + isLeftValid = false; + } + if(root->right != NULL){ + isRightValid = true; + if(!canSwapToBST(root->right, rightMax, rightMin)){ + return false; + } + }else{ + isRightValid = false; + } + //now we can know that the left and right sub-tree are NULL or BST + if(isLeftValid && isRightValid){ + if(leftMax < root->val && rightMin > root->val + ||rightMax < root->val && leftMin > root->val){ + maxVal = max(leftMax, rightMax); + minVal = min(leftMin, rightMin); + return true; + }else{ + return false; + } + }else if(isLeftValid){ + if(leftMax < root->val || leftMin > root->val){ + maxVal = max(root->val, leftMax); + minVal = min(root->val, leftMin); + return true; + }else{ + return false; + } + }else if(isRightValid){ + if(rightMin > root->val || rightMax < root->val){ + maxVal = max(root->val, rightMax); + minVal = min(root->val, rightMin); + return true; + }else{ + return false; + } + }else{ + //leaf node + maxVal = minVal = root->val; + return true; + } +} +``` \ No newline at end of file From 5b09468a3a3e887c148c7f4c425312adea911b15 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 14 Nov 2014 19:29:15 +0800 Subject: [PATCH 316/327] Done. fix #15 --- Tree & Linkedlist.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index 37fb700..3ee84c9 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -9,7 +9,7 @@ Index: -[Leetcode:Flatten Binary Tree to Linked List](#Anchor6) -[Leetcode:Construct Binary Tree from Inorder and Postorder Traversal](#Anchor7) -[Leetcode:Recover Binary Search Tree](#Anchor8) --[*TODO*::LeetCode:Binary Tree Maximum Path Sum](#Anchor9) +-[LeetCode:Binary Tree Maximum Path Sum](#Anchor9) -[Judge one tree is BST under swap operation](#Anchor10) ------- @@ -319,6 +319,45 @@ public: -**[LeetCode:Binary Tree Maximum Path Sum](http://oj.leetcode.com/problems/binary-tree-maximum-path-sum/)**([Back to Index](#AnchorIndex)) +利用find()方法返回值携带以当前节点向根节点出发的简单路径的最大值,利用传引用携带求解的最大路径值。 + +简单路径的最大值的更新方法为从下述3个值中取最大: + + * 当前节点值 + * 当前节点 + 左子树中简单路径的最大值(包含左子树根节点) + * 当前节点 + 右子树中简单路径的最大值(包含右子树根节点) + +最大路径(求解值)的更新方法为从下述6个值中取最大: + + * 左子树最大路径 + * 右子树最大路径 + * 根节点值 + * 根节点值 + 左子树简单路径最大值 + * 根节点值 + 右子树简单路径最大值 + * 根节点值 + 左子树简单路径最大值 + 右子树简单路径最大值 + +```cpp +int maxPathSum(TreeNode *root) { + int pathMax = 0x80000000; + find(root, pathMax); + return pathMax; +} + +int find(TreeNode * root, int & pathMax){ + if(root == NULL){ + return 0; + } + int leftMax = find(root->left, pathMax); // simple path + int rightMax = find(root->right, pathMax); + int ret = max(leftMax + root->val, rightMax + root->val); + ret = max(ret, root->val); + int tempMax = max(root->val , root->val + leftMax); + tempMax = max(tempMax, tempMax + rightMax); + pathMax = max(pathMax, tempMax); + return ret; +} +``` + ------- -**[Judge one tree is BST under swap operation]**([Back to Index](#AnchorIndex)) From ff84e5bf18f4c86013e1e45c12050453cef858f5 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Fri, 14 Nov 2014 19:31:41 +0800 Subject: [PATCH 317/327] Fix error in Tree & Linkedlist.md --- Tree & Linkedlist.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tree & Linkedlist.md b/Tree & Linkedlist.md index 3ee84c9..2f46ea7 100644 --- a/Tree & Linkedlist.md +++ b/Tree & Linkedlist.md @@ -319,9 +319,9 @@ public: -**[LeetCode:Binary Tree Maximum Path Sum](http://oj.leetcode.com/problems/binary-tree-maximum-path-sum/)**([Back to Index](#AnchorIndex)) -利用find()方法返回值携带以当前节点向根节点出发的简单路径的最大值,利用传引用携带求解的最大路径值。 +利用find()方法返回值携带以当前节点向叶子节点出发的简单路径的最大值,利用传引用携带求解的最大路径值。 -简单路径的最大值的更新方法为从下述3个值中取最大: +包含当前节点的简单路径的最大值的更新方法为从下述3个值中取最大: * 当前节点值 * 当前节点 + 左子树中简单路径的最大值(包含左子树根节点) From 12f7ba4c42a874dd23cf2d4943088248545d5f3e Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Sat, 15 Nov 2014 15:46:38 +0800 Subject: [PATCH 318/327] Done. fix #10 --- Dynamic Programming.md | 56 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 909ea45..54d71cd 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -12,7 +12,7 @@ Index: -[LCS](#Anchor9) -[*TODO*::LIS](#Anchor10) -[LeetCode:Edit Distance](#Anchor11) --[*TODO*::LeetCode:Palindrome Partitioning](#Anchor12) +-[LeetCode:Palindrome Partitioning](#Anchor12) -[Divide Array To Make Two Equal Part](#Anchor13) ------- @@ -509,6 +509,60 @@ public: -**[LeetCode:Palindrome Partitioning](http://oj.leetcode.com/problems/palindrome-partitioning/)([Back to Index](#AnchorIndex)) +首先使用dp的方式获得字符串s的任意子串是否为回文串,这个过程会花费O(n^2)的时间,其中n为字符串s的长度。dp[i][j]表示下标从i到j的子串是否为回文串,递归转移方程如下: + + * dp[i][j] = true , if s[i] == s[j] && (j-i <= 1 || dp[i+1][j-1] == true) + = false , otherwise + +```cpp +bool dp[n][n]; +void CalculateIsPalindrome(){ + for(int i = n-1; i >=0 ; i--){ + for(int j = i; j <= n-1; j++){ + if(s[i] == s[j] && (j - i <= 1 || dp[i+1][j-1] == true)){ + dp[i][j] = true; + }else{ + dp[i][j] = false; + } + } + } +} +``` + +接下来使用DFS求解,每次递归中对当前字符串取从头部开始的子串,如果该子串为回文串,则对剩余部分进行递归。 + +```cpp +class Solution { +public: + vector> partition(string s) { + vector trace; + vector> ret; + + int n = s.size(); + if(n == 0) return ret; + CalculateIsPalindrome(); + dfs(s, 0, ret, trace); + } + + void dfs(string s, int index, vector> &ret, vector &trace){ + int n = s.size(); + if(index == n){ + ret.push_back(trace); + return; + } + for(int i = index; i <= n-1; i++){ + string sub = s.substr(index,i-index+1); + if(isPal[index][i] == 1){ + trace.push_back(sub); + find(s, i+1, ret, trace, isPal); + trace.pop_back(); + } + } + return; + } +}; + +``` ------- -**[Divide Array To Make Two Equal Part]([Back to Index](#AnchorIndex)) From f22d8017928f6756c0a884fc7b5e121fa7576bcc Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Sat, 15 Nov 2014 16:12:54 +0800 Subject: [PATCH 319/327] Done. fix #7 --- Dynamic Programming.md | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 54d71cd..143cd1a 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -6,7 +6,7 @@ Index: -[LeetCode:Interleaving String](#Anchor3) -[LeetCode:Wildcard Matching](#Anchor4) -[LeetCode:Trapping Rain Water](#Anchor5) --[*TODO*::Leetcode:Palindrome Partitioning II](#Anchor6) +-[Leetcode:Palindrome Partitioning II](#Anchor6) -[*TODO*::Leetcode:Longest Palindromic Substring](#Anchor7) -[Leetcode:Distinct Subsequences](#Anchor8) -[LCS](#Anchor9) @@ -254,6 +254,42 @@ public: -**[Leetcode:Palindrome Partitioning II](http://oj.leetcode.com/problems/palindrome-partitioning-ii/)**([Back to Index](#AnchorIndex)) +参考[LeetCode:Palindrome Partitioning](#Anchor12)的做法可以在O(n^2)的时间内求出字符串s的所有子串是否为回文串的信息,matrix[i][j]表示字符串s的下标从i到j的子串是否为回文串,dp转移方程略。 + +在获得上述信息的情况下,使用另外一个一维数组来求解最小切分数。dp[i]表示下标从i到len-1的子串能够被分为多少个回文断,则我们要求解的最终目标变成了dp[0]-1,该dp转移方程为: + + * dp[i] = min(dp[i], dp[j+1]+1), if matrix[i][j] == true + +每当我们确定i到j为一个回文子串,我们尝试比较dp[i]和dp[j+1]+1的值,最终求出目标值。 + +```cpp +class Solution { +public: + int minCut(string s) { + int len = s.size(); + int* dp = new int[len+1]; + for(int i=len; i>=0; i--) + dp[i] = len-i; + bool** matrix = new bool*[len]; + for(int i=0; i=0; i--) + for(int j=i; j -**[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/)**([Back to Index](#AnchorIndex)) @@ -542,6 +578,7 @@ public: if(n == 0) return ret; CalculateIsPalindrome(); dfs(s, 0, ret, trace); + return ret; } void dfs(string s, int index, vector> &ret, vector &trace){ From 11a41d8e1bcb8c734493f7965c905b7b091caacb Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Sat, 15 Nov 2014 22:39:38 +0800 Subject: [PATCH 320/327] Basic solution done. Need O(nlogn) algorithm that can work out LIS --- Dynamic Programming.md | 110 ++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/Dynamic Programming.md b/Dynamic Programming.md index 143cd1a..eb69a78 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -10,7 +10,7 @@ Index: -[*TODO*::Leetcode:Longest Palindromic Substring](#Anchor7) -[Leetcode:Distinct Subsequences](#Anchor8) -[LCS](#Anchor9) --[*TODO*::LIS](#Anchor10) +-[LIS](#Anchor10) -[LeetCode:Edit Distance](#Anchor11) -[LeetCode:Palindrome Partitioning](#Anchor12) -[Divide Array To Make Two Equal Part](#Anchor13) @@ -442,67 +442,87 @@ public class MyOwn { for (i = l.size() - 1; i >= 0; i--) System.out.print(a[l.get(i)] + " "); } - - public static void main(String[] args) { - MyOwn m = new MyOwn(); - char[] a = { 'c', 'n', 'b', 'l', 'o', 'g', 's' }; - char[] b = { 'b', 'e', 'l', 'o', 'n', 'g' }; - m.LCS(a, b); - } } ``` ------- -**[LIS]**([Back to Index](#AnchorIndex)) -最长上升子序列(LIS),给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1,s2,s3…sn递增并且这个子序列的长度最长。输出这个最长的长度。 +最长上升子序列(LIS),给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1,s2,s3…sn递增并且这个子序列的长度最长。输出这个最长的长度。等效问题:求解一个数列中需要调整(取出一个数并插入新的位置)的最少次数使得该数列有序,一次调整操作如将1,2,4,6,5,3变换为1,2,3,4,6,5。 -又一个经典的动态规划问题。不同的是这次使用的是一维数组,空间复杂度下降了,dp依旧记录状态,只不过记录的状态很特别,dp[i] -=j表示长度为i的递增子序列的最后一个数是j。在对原数组遍历的过程中,每一次都要将a[i]更新到dp的对应位置去。比如a[4]=3,而dp[1]=2,dp[2]=4,表示长度为1的递增子序列最后一个数是2,长度为2的递增子序列最后一个数是4,此时就可以将dp[2]更新为3,因为长度为1的递增子序列最后一位为2,3大于2,所以序列长度加一,最后一位为3,3小于4,所以将dp[2]更新为3.由此可见dp是一个单调递增数组,所以在修改的时候可以采用二分查找,这样时间复杂度就降为nlogn。如果dp中没有比a[i]大的,则说明最长递增子序列的长度增加了一位。 +如果仅仅是求解LIS的长度,可以使用一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素大的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4。但需要注意的是,该算法结束后栈内的序列并不是我们所求的LIS,仅仅是长度相同而已。 -Add by[@sc703bupt](https://github.com/sc703bupt): 实际上[@popolou](https://github.com/popolou)的解法是贪心法,使用了一个栈模拟当前最大递增子序列的长度,当元素大于栈顶,最长序列+1,否则替换第一个比该元素大的栈内元素,保持栈内序列的“最大潜力”,该解法的时间复杂度为O(nlgn)。例如对于1,2,3,6,4序列,1、2和3顺序入栈,代表当前最大长度为3,当遍历到6时,仍然大于栈顶,入栈,当前最大长度为4,当遍历到4时,寻找第一个比4大的元素并替换,栈内为1,2,3,4,故最大长度为4 +```cpp +int LIS(int A[], int n){ + vector vec;//这里我们是用一个vector来模拟stack,方便二分查找 + for(int i= 0; i <= n-1;i++){ + if(vec.empty()||A[i]>=vec.back()){ + vec.push_back(A[i]); + }else{ + int start = 0, end = vec.size()-1; + while(start <= end){ + if(start == end){ + if(vec[start] > A[i]){ + vec[start] = A[i]; + }else if(vec[start] A[k], 0 <= i <= n-1 -```java -import java.util.ArrayList; +同时因为我们需要求解该LIS序列,则使用lastPos[i]来记录以A[i]结尾的最长上升子序列的倒数第二元素的位置,也即该上升序列中排在A[i]前一个的元素,每次更新dp[i]时更新lastPos[i],在计算dp[i]完成后,从后向前还原LIS序列。 -public class MyOwn1 { - public void LIS(int[] a) { - int len = a.length; - int[] b = new int[len + 1]; - b[1] = a[0]; - int max = 1; - ArrayList result = new ArrayList(); - for (int i = 1; i < len; i++) { - int start = 1; - int end = max; - while (start <= end) { - int middle = (start + end) / 2; - if (b[middle] < a[i]) - start = middle + 1; - else if (b[middle] > a[i]) - end = middle - 1; - } - b[start] = a[i]; - if (start > max) { - max++; - result.clear(); - for (int j = 1; j <= max; j++) - result.add(b[j]); +```cpp +vector LIS(int A[], int n){ + if(n <= 0) return; + int dp[n]; // dp[i] records len of LIS using A[i] as the last element + int lastPos[n]; // lastPos[i] records the previous element in the LIS using A[i] as the last element + for(int i = 0; i <= n-1; i++){ + dp[i] = 1;// at least 1 + lastPos[i] = 0;// whatever + } + int lenOfMaxLIS = 0, lastPosOfMaxLIS = 0; + for(int i = 1; i <= n-1; i++){ + for(int j = 0; j <= i-1; j++){ + if(A[j] > A[i] && dp[j] + 1 > dp[i]){ + dp[i] = dp[j] + 1; + lastPos[i] = j; + if(dp[i] > lenOfMaxLIS){ // update global info + lenOfMaxLIS = dp[i]; + lastPosOfMaxLIS = i; + } } } - System.out.println("result: " + max); - System.out.println(result); } - - public static void main(String[] args) { - MyOwn1 m = new MyOwn1(); - int[] a = { 2, 1, 5, 3, 6, 4, 8, 9, 7 }; - m.LIS(a); + vector lisVector; + for(int i = lastPosOfMaxLIS; i >= 0; ){ + lisVector.push_back(A[i]); + i = lastPos[i]; } + reverse(lisVector.begin(), lisVector.end()); + return lisVector; } ``` +那么求解LIS序列也存在O(nlogn)的解法,使用了特殊的数据结构,待续。 ------- From 69a76af4c3bd6f460ff78b50f513e9280cf31cf8 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Mon, 17 Nov 2014 11:11:25 +0800 Subject: [PATCH 321/327] Done. add 2 pics and fix #8 --- Dynamic Programming.md | 119 +++++++++++++++++++++------------- Image/picForManacherCase1.png | Bin 0 -> 9895 bytes Image/picForManacherCase2.png | Bin 0 -> 9898 bytes 3 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 Image/picForManacherCase1.png create mode 100644 Image/picForManacherCase2.png diff --git a/Dynamic Programming.md b/Dynamic Programming.md index eb69a78..7da3394 100644 --- a/Dynamic Programming.md +++ b/Dynamic Programming.md @@ -7,7 +7,7 @@ Index: -[LeetCode:Wildcard Matching](#Anchor4) -[LeetCode:Trapping Rain Water](#Anchor5) -[Leetcode:Palindrome Partitioning II](#Anchor6) --[*TODO*::Leetcode:Longest Palindromic Substring](#Anchor7) +-[Leetcode:Longest Palindromic Substring](#Anchor7) -[Leetcode:Distinct Subsequences](#Anchor8) -[LCS](#Anchor9) -[LIS](#Anchor10) @@ -294,56 +294,85 @@ public: -**[Leetcode:Longest Palindromic Substring](http://oj.leetcode.com/problems/longest-palindromic-substring/)**([Back to Index](#AnchorIndex)) -普通的方法n方时间复杂度是不可取的。这里介绍一种O(n)的方法。本方法使用之前计算过的回文长度计算以当前字符为中心的最大回文长度。首先进行预处理,预处理的目的是计算回文时不分开考虑奇偶的情况。保存两个变量,C为中轴,R为最右,R以C为轴对称。每次遍历到i,计算出i相对于轴C的镜像i'。因为R以C为轴对称,所以以i为中心的回文串长度是R-i和以i'为中心回文串长度的最小值。之后长度若能扩展则继续扩展。然后根据i更新最右R。 +O(n^3)暴力法略过不提,O(n^2)的方法可以参考[LeetCode:Palindrome Partitioning](#Anchor12),在计算所有子串是否是回文串的过程中得到最长回文子串。 + +下面介绍的方法为Manacher算法,可以在O(n)时间内求出最长回文子串。该算法的核心思想是**利用已有的最长回文子串简化后续求解过程**。首先定义三个变量: + + * lpsCenter: 已有的最长回文子串的中心位置 + * lpsRadius: 已有的最长回文子串的半径(从中心位置到边缘,包括中心位置) + * P[i]: 记录了以下标i为中心的最长回文子串的半径 + +另外,需要对原字符串做一定的预处理,也即在原字符串中插入特定字符(如'#')使得我们总是在处理长度为奇数的字符串,统一了奇偶情况: + + * "abcde" => "#a#b#c#d#e#" + * "abba" => "#a#b#b#a#" + +如果算法能够得到lpsCenter和lpsRadius,就能够还原出原字符串中的最长回文子串。接下来将结合图片来解释该算法的核心。 + +当我们已经得到以0到i-1下标为中心的最长回文子串半径P[k], k∈[0,i-1],且从中得到了lpsCenter和lpsRadius,若i满足一定条件时,则计算P[i]时可以利用已有的信息。对于Case 1,j为i关于lpsCenter对称位置,也即 + + * lpsCenter - j == i - lpsCenter => j = 2 * lpsCenter - i + +![Manacher Case 1](Image/picForManacherCase1.png "Manacher Case 1") + +在Case 1,容易看出以j为中心的回文子串保证了以i为中心也**至少**存在相同的回文子串,这是由于当前最长回文子串的lpsRadius(实际上就是P[lpsCenter])与P[j]的大小关系决定了,也即**P[i] >= P[j]** + +![Manacher Case 2](Image/picForManacherCase2.png "Manacher Case 2") + +在Case 2,当前最长回文子串的lpsRadius与P[j]的大小关系无法保证以i为中心的回文子串与以j为中心的一致,则此时**P[i] >= mx-i** + +对于i < mx 而言,上述两种情况仅仅是得到了P[i]的下界,对于i+P[i]和i-P[i]以外的情况,仍然需要逐个字符比较得到。 + +如果i本身已经超出当前最大回文子串的覆盖半径(i >= mx)如何处理?简单的令P[i] = 1,接下来逐字符比较即可。 ```cpp -class Solution { -public: - // Transform S into T. - // For example, S = "abba", T = "^#a#b#b#a#$". - // ^ and $ signs are sentinels appended to each end to avoid bounds checking - - string preProcess(string s) { - int n = s.length(); - if (n == 0) return "^$"; - string ret = "^"; - for (int i = 0; i < n; i++) ret += "#" + s.substr(i, 1); - ret += "#$"; - return ret; +// Suppose we have no '#' in the original string s +string LPS(string s){ + if(s.size() == 0) return ""; + string t = preProcess(s); + int n = t.size(); + int P[n]; + memset(P, 0, sizeof(P)); + int mx = 0, lpsCenter = 0; + for(int i = 1; i <= n-1; i++){ + int j = 2 * lpsCenter - i; + if(mx > i){ + P[i] = min(P[j], mx - i); + }else{ + P[i] = 1; + } + //Search more + while(t[i-P[i]] == t[i+P[i]]){ + P[i]++; + } + //Update global info + if(i+P[i] > mx){ + mx = i + P[i]; + lpsCenter = i; + } } - string longestPalindrome(string s) { - string T = preProcess(s); - const int n = T.length(); - // 以T[i] 为中心,向左/右扩张的长度,不包含T[i] 自己, - // 因此P[i] 是源字符串中回文串的长度 - int P[n]; - int C = 0, R = 0; - for (int i = 1; i < n - 1; i++) { - int i_mirror = 2 * C - i; // equals to i' = C - (i-C) - P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; - // Attempt to expand palindrome centered at i - while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) - P[i]++; - // If palindrome centered at i expand past R, - // adjust center based on expanded palindrome. - if (i + P[i] > R) { - C = i; - R = i + P[i]; - } - } - // Find the maximum element in P. - int max_len = 0; - int center_index = 0; - for (int i = 1; i < n - 1; i++) { - if (P[i] > max_len) { - max_len = P[i]; - center_index = i; - } + //get the LPS in the original string s + string ret; + for(int i = lpsCenter - P[lpsCenter] + 1; i <= lpsCenter + P[lpsCenter] -1; i++){ + if(t[i] != '#'){ + ret += t[i]; } - return s.substr((center_index - 1 - max_len) / 2, max_len); } -}; + return ret; +} + +// Add '#' in the original string and return +string preProcess(string s){ + string ret; + ret += '#' + for(int i = 0; i <= s.size()-1; i++){ + ret += s[i]; + ret += '#'; + } + return ret; +} + ``` ------- diff --git a/Image/picForManacherCase1.png b/Image/picForManacherCase1.png new file mode 100644 index 0000000000000000000000000000000000000000..1470b15fb8e43831e22ef76f1d056bbbbc305380 GIT binary patch literal 9895 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 Date: Mon, 17 Nov 2014 20:37:23 +0800 Subject: [PATCH 322/327] add two questions in Array & String.md --- Array & String.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Array & String.md b/Array & String.md index 4956bcf..306f293 100644 --- a/Array & String.md +++ b/Array & String.md @@ -23,7 +23,8 @@ Index: -[Leetcode:Regular Expression Matching](#Anchor20) -[Leetcode:Simplify Path](#Anchor21) -[Leetcode:Text Justification](#Anchor22) - +-[Leetcode:Search for a Range](#Anchor23) +-[Leetcode:Minimum Window Substring](#Anchor24) ------- -**[Leetcode:single number II](http://oj.leetcode.com/problems/single-number-ii/)**([Back to Index](#AnchorIndex)) @@ -1144,4 +1145,13 @@ public class Solution { return s; } } -``` \ No newline at end of file +``` + +------- + +-**[Leetcode:Search for a Range](https://oj.leetcode.com/problems/search-for-a-range/)**([Back to Index](#AnchorIndex)) + + +------- + +-**[Leetcode:Minimum Window Substring](https://oj.leetcode.com/problems/minimum-window-substring/)**([Back to Index](#AnchorIndex)) From db56ab5d96f2bf23789ddf8017a4518cc4157ed7 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Sun, 8 Feb 2015 23:19:02 +0800 Subject: [PATCH 323/327] add Git Note & Cheatsheet.md --- Git Note & Cheatsheet.md | 28 ++++++++++++++++++++++++++++ README.md | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 Git Note & Cheatsheet.md diff --git a/Git Note & Cheatsheet.md b/Git Note & Cheatsheet.md new file mode 100644 index 0000000..3a416e2 --- /dev/null +++ b/Git Note & Cheatsheet.md @@ -0,0 +1,28 @@ +##Greedy Strategy + +本文是在阅读完OSChina对Pro Git的翻译版后整理的笔记和Cheatsheet。 +[OSChina Progit阅读地址](http://git.oschina.net/progit/) +[Github Progit托管地址](https://github.com/progit/progit) + +------- +###命令速记 +`git config --global user.name [username]` :指定提交用户名 +`git config --global user.email [email]` :指定提交用邮箱 +`git config --global core.editor [editor]` :指定编辑器 +`git config --global merge.tool [mergetool]` :指定合并工具 +`git config --list` :查询所有的Git配置信息 +`git config [setting option]` :查询某配置信息,如user.name +`git clone [target git repository]` :从目标克隆指定仓库 +`git add [file/folder]` : + +------- +###配置文件 +/etc/gitconfig :适用于系统中所有用户,由`git config --system`写入 +~/.gitconfig :适用于当前用户,由`git config --global`写入 +./.git/config :适用于当前项目 + +注意,配置文件的优先级随覆盖范围降低而升高 + +------- +###底层原理速记 +[TODO] \ No newline at end of file diff --git a/README.md b/README.md index 9e9b82f..9eba1f3 100644 --- a/README.md +++ b/README.md @@ -20,14 +20,14 @@ Chapters 9. [Probability](Probability.md) 10. [Others](Others.md) -####Engineering -1. Website construction +####Engineering ####Basic Knowledge 1. [Basic Java Concepts](Basic Java Concepts.md) 2. [NIO](NIO.md) 3. [Big Data Processing](Big Data Processing.md) 4. [Functions In string.h](Functions in string.h.md) +5. [Git Note & Cheatsheet](Git Note & Cheatsheet.md) Core contributors ------------ From 6ff6a6457eaa77d639ea30dce712865d45adc6c2 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 10 Feb 2015 21:34:16 +0800 Subject: [PATCH 324/327] test --- Git Note & Cheatsheet.md | 10 ++++++++-- test | 0 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 test diff --git a/Git Note & Cheatsheet.md b/Git Note & Cheatsheet.md index 3a416e2..74582b0 100644 --- a/Git Note & Cheatsheet.md +++ b/Git Note & Cheatsheet.md @@ -1,4 +1,4 @@ -##Greedy Strategy +##Git Note & Cheatsheet 本文是在阅读完OSChina对Pro Git的翻译版后整理的笔记和Cheatsheet。 [OSChina Progit阅读地址](http://git.oschina.net/progit/) @@ -13,7 +13,13 @@ `git config --list` :查询所有的Git配置信息 `git config [setting option]` :查询某配置信息,如user.name `git clone [target git repository]` :从目标克隆指定仓库 -`git add [file/folder]` : +`git init` :Git仓库初始化 +`git add [file/folder]` :将指定文件加入暂存区 +`git status` :查看暂存区状态 +`git diff` :比较**工作目录**和**暂存区快照**的差异 +`git diff --staged` :比较**上次提交的快照**和**暂存区快照**的差异 +`git commit -m [commit message]` :提交暂存区中的文件 +`git commit -a` :git add -A + git commit ------- ###配置文件 diff --git a/test b/test new file mode 100644 index 0000000..e69de29 From 5212b6420b242da7e049daf57e29d97a3edeac46 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Tue, 10 Feb 2015 21:34:37 +0800 Subject: [PATCH 325/327] remove test --- test | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test diff --git a/test b/test deleted file mode 100644 index e69de29..0000000 From 855a3cba331a512d1dce76f9169a251fb283cc55 Mon Sep 17 00:00:00 2001 From: sc703bupt Date: Thu, 12 Feb 2015 17:39:18 +0800 Subject: [PATCH 326/327] partially done. --- Git Note & Cheatsheet.md | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/Git Note & Cheatsheet.md b/Git Note & Cheatsheet.md index 74582b0..8d43275 100644 --- a/Git Note & Cheatsheet.md +++ b/Git Note & Cheatsheet.md @@ -6,20 +6,41 @@ ------- ###命令速记 -`git config --global user.name [username]` :指定提交用户名 -`git config --global user.email [email]` :指定提交用邮箱 -`git config --global core.editor [editor]` :指定编辑器 -`git config --global merge.tool [mergetool]` :指定合并工具 +`git config --global user.name ` :指定提交用户名 +`git config --global user.email ` :指定提交用邮箱 +`git config --global core.editor ` :指定编辑器 +`git config --global merge.tool ` :指定合并工具 `git config --list` :查询所有的Git配置信息 -`git config [setting option]` :查询某配置信息,如user.name -`git clone [target git repository]` :从目标克隆指定仓库 +`git config ` :查询某配置信息,如user.name +`git clone ` :从目标克隆指定仓库 `git init` :Git仓库初始化 -`git add [file/folder]` :将指定文件加入暂存区 +`git add ` :将指定文件加入暂存区 `git status` :查看暂存区状态 `git diff` :比较**工作目录**和**暂存区快照**的差异 `git diff --staged` :比较**上次提交的快照**和**暂存区快照**的差异 -`git commit -m [commit message]` :提交暂存区中的文件 -`git commit -a` :git add -A + git commit +`git commit -m ` :提交暂存区中的文件 +`git commit -a` :git add -A + git commit +`git commit -amend` :提交暂存区中的文件,并与上一次提交合并 +`git rm ` :删除已被跟踪的文件 +`git rm --cached ` :将已被跟踪的文件移出跟踪列表(不删除) +`git mv ` :移动文件并加入暂存区 +`git log` :显示日志 +`git log -p -2` :展开显示每次提交的内容差异,仅显示最近的两次提交 +`git log --stat` :仅显示媒体提交的改动行数 +`git log --pretty=oneline` :仅显示SHA和提交信息 +`git log --pretty=format:"%h - %an, %ar : %s"` :以定制格式显示提交历史 +`git log --graph` :以图表形式显示提交历史 +`git reset HEAD ` :取消对该文件的追踪 +`git checkout -- ` : 将该文件恢复为上次提交快照版本 +`git remote -v` :查看所有远程仓库名称和对应的url +`git remote add ` :添加远程仓库 +`git remote show ` :显示远程仓库详细信息 +`git remote rename ` :变更远程仓库名称 +`git remote rm ` :移除指定远程仓库 +`git fetch ` :抓取指定远程仓库到本地 +`git pull ` :git fetch + git merge +`git push ` :将当前分支推送到指定仓库中指定名称分支 + ------- ###配置文件 From 1a865f4b70f0079582672ce73ccd941edc9fbe99 Mon Sep 17 00:00:00 2001 From: shenchen Date: Tue, 17 Feb 2015 14:16:34 +0800 Subject: [PATCH 327/327] Git Note & Cheatsheet.md done. --- Git Note & Cheatsheet.md | 65 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/Git Note & Cheatsheet.md b/Git Note & Cheatsheet.md index 8d43275..d89ea47 100644 --- a/Git Note & Cheatsheet.md +++ b/Git Note & Cheatsheet.md @@ -5,19 +5,23 @@ [Github Progit托管地址](https://github.com/progit/progit) ------- -###命令速记 +###常用命令速记 `git config --global user.name ` :指定提交用户名 `git config --global user.email ` :指定提交用邮箱 `git config --global core.editor ` :指定编辑器 `git config --global merge.tool ` :指定合并工具 `git config --list` :查询所有的Git配置信息 `git config ` :查询某配置信息,如user.name +`git config alias. ''` :设置自定义命令 `git clone ` :从目标克隆指定仓库 `git init` :Git仓库初始化 `git add ` :将指定文件加入暂存区 +`git add -i` :交互式shell模式 `git status` :查看暂存区状态 `git diff` :比较**工作目录**和**暂存区快照**的差异 `git diff --staged` :比较**上次提交的快照**和**暂存区快照**的差异 +`git diff --check` :显示多余白字符 +`git diff ...` :特性分支相对于两个分支共同祖先将要引入的新代码 `git commit -m ` :提交暂存区中的文件 `git commit -a` :git add -A + git commit `git commit -amend` :提交暂存区中的文件,并与上一次提交合并 @@ -32,15 +36,47 @@ `git log --graph` :以图表形式显示提交历史 `git reset HEAD ` :取消对该文件的追踪 `git checkout -- ` : 将该文件恢复为上次提交快照版本 +`git checkout ` :切换到指定分支 +`git branch ` :默认以当前分支为原型创建新分支 +`git branch -d ` :删除指定分支 +`git branch --no-merged` :查看尚未于当前分支合并的分支 +`git checkout -b ` :git branch + git checkout +`git checkout -b ` :以远程分支为原型创建新分支 `git remote -v` :查看所有远程仓库名称和对应的url `git remote add ` :添加远程仓库 `git remote show ` :显示远程仓库详细信息 `git remote rename ` :变更远程仓库名称 `git remote rm ` :移除指定远程仓库 `git fetch ` :抓取指定远程仓库到本地 +`git merge ` :将指定分支合并到当前分支 `git pull ` :git fetch + git merge -`git push ` :将当前分支推送到指定仓库中指定名称分支 - +`git push ` :将当前分支推送到指定仓库中的同名分支 +`git push :` :推送指定分支到指定仓库的指定分支(如本地分支留空则为删除远程分支www) +`git tag` :列出所有标签 +`git tag -l ` :列出符合匹配模式的标签 +`git tag ` :创建指定名称的标签 +`git tag -v ` :验证标签 +`git push ` :推送标签(git push默认不推送) +`git push --tags` :推送所有标签 +`git rebase ` :以指定的分支与当前分支的公共祖先A为基准,将当前分支相对于A的变动重新应用于指定分支。衍合操作使得当前分支成为指定分支的快进版本,但同时使得当前分支之前的提交对象悬空,并会导致远程分支失效,因此最好不要对公开分支做衍合操作。 +`git rebase ` :作用同上 +`git rebase -i >` :在衍合最近N次提交的同时对提交对象进行交互式操作 +`git request-pull ` :请求合并本地分支 +`git format-patch ` :生成.patch补丁文件 +`git am *.patch` :应用.patch补丁文件 +`git merge-base ` :得到两个分支的合并基准 +`git cherry-pick ` :只合并某次提交 +`git reflog` :HEAD分支的变动记录 +`git show HEAD^` :查看HEAD指向提交的第N父提交,N留空则为第一父提交 +`git show HEAD~` :查看HEAD指向提交的前N父提交,如HEAD~3等价于HEAD^^^ +`git stash` :将当前的变更工作进行储藏 +`git stash list` :列出所有储藏 +`git stash apply ` :应用指定的储藏,如果留空则应用最近的储藏。注意,该命令会将未提交的文件自动提交,如果想完全还原之前的场景,则应使用--index选项。 +`git blame -L ` :查看指定文件从aa到bb行的历史修改 +`git bisect start` :启动Git的提交对象二分查找 +`git bisect ` :表示当前版本为好/坏版本 +`git bisect reset` :重置HEAD,**注意,在使用二分查找功能后必须使用该命令重置** +`git show-ref` :查看所有引用的全名 ------- ###配置文件 @@ -51,5 +87,24 @@ 注意,配置文件的优先级随覆盖范围降低而升高 ------- -###底层原理速记 -[TODO] \ No newline at end of file +###Git的.git目录 +HEAD :指向当前被检出的分支 +config :当前项目的配置文件 +description :供GitWeb程序使用的描述文件 +hooks/ :用于保存客户端或服务端的钩子脚本 +index :保存暂存区信息 +info/ :保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可执行文件 +objects/ :存储对象,包括blob对象,tree对象,commit对象和tag对象 +refs/ :存储分支信息 + +------- +###使用Git底层命令完成版本流程 +1.创建一个Git文件对象 :`echo 'test content' | git hash-object -w --stdin`,其中-w保证写入该对象,--stdin使用标准输入流作为文件内容 +2.输出该Git文件对象内容 :`git cat-file -p ` +3.将单个文件加入暂存区 :`git update-index --add --cacheinfo 100644 `,由于该文件原先并不在暂存区域中 ,必须传入 --add 参数;由于要添加的文件并不在当前目录下而是在数据库中,必须传入 --cacheinfo 参数。同时指定了文件模式,SHA-1 值和文件名。 +4.使用暂存区的文件生成tree对象 :`git write-tree` +5.生成commit对象并指向指定的tree对象 :`echo 'first commit' | git commit-tree `。也可以使用`git commit-tree -p `指定父提交。 +6.生成master分支并将其指向特定的commit对象 :`git update-ref refs/heads/master ` +7.查看HEAD的值 :`git symbolic-ref HEAD` +8.设置HEAD的值 :`git symbolic-ref HEAD ` +