diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7bcc29a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.DS_Store
+GenerateCodeTable.class
+GenerateCodeTable$TableRow.class
+gh-md-toc
+Solution.class
diff --git a/GenerateCodeTable.class b/GenerateCodeTable.class
deleted file mode 100644
index da90633..0000000
Binary files a/GenerateCodeTable.class and /dev/null differ
diff --git a/GenerateCodeTable.java b/GenerateCodeTable.java
index d89f687..ea8173a 100644
--- a/GenerateCodeTable.java
+++ b/GenerateCodeTable.java
@@ -1,113 +1,451 @@
-import java.io.*;
-/*
-Used to generate table of contents.
-1. No args: generate GitHub table
-2. args == 'word', generate WordPress table.
-3. args == 'all', genereate both table
-*/
-public class GenerateCodeTable {
- public static void main(String[] args) {
- //Read Java Solution Folder
- File folder = new File("./Java");//"." = current path
- if (!folder.exists() || !folder.isDirectory()) {
- System.out.println("Check Directory:1");
- return;
- }
- File[] listOfFiles = folder.listFiles();
- if (listOfFiles == null) {
- System.out.println("Check Directory:2");
- return;
- }
-
- String outputContent = "";
- File outFile;
-
- if (args.length == 0){
- outputContent = generateREADME(listOfFiles);
- printTable("README.md", outputContent);
- } else if (args != null && args[0].contains("word")) {//Wordpress
- outputContent = generateWordPressPage(listOfFiles);
- printTable("WordPress.txt", outputContent);
- } else if (args != null && args[0].contains("all")) {
- outputContent = generateREADME(listOfFiles);
- printTable("README.md", outputContent);
- outputContent = generateWordPressPage(listOfFiles);
- printTable("WordPress.txt", outputContent);
- } else {
- return;
- }
-
-
- }
-
- public static String generateWordPressPage(File[] listOfFiles) {
- //Assemble output
- String outputContent = "Java Solutions to problems from LintCode(http://LintCode.com).\n" +
- "
" +
- "" +
- "" +
- "# | " +
- "Problem | " +
- " Level | " +
- " Language | " +
- "
" +
- "" +
- "";
-
- int count = 0;
- for (File file : listOfFiles) {
- if (file.getName().contains(".java")) {
- //outputContent += "|" + count + "|[" + file.getName() + "](https://github.com/shawnfan/LintCode/blob/master/Java/"+ file.getName() +")| |" + "Java|\n";
- outputContent+=
- "" +
- "" + count + " | " +
- "" + file.getName() + " | " +
- " | " +
- "Java | " +
- "
";
- count++;
- }
- }
-
- outputContent += "
";
- return outputContent;
- }
-
-
- /*
- Generate GitHub ReadMe file
- */
- public static String generateREADME(File[] listOfFiles) {
- //Assemble output
- String outputContent = "# LintCode\n\n" +
- "To host Java Solutions to problems from LintCode(http://LintCode.com).\n" +
- "I Will try to revise the solutions once new problem or new testing case occurs.\n\n" +
- "| Squence | Problem | Level | Language |\n" +
- "|:-------:|:--------------|:---------------|:---------:|\n";
- int count = 0;
- for (File file : listOfFiles) {
- if (file.getName().contains(".java")) {
- outputContent += "|" + count + "|[" + file.getName() + "](https://github.com/shawnfan/LintCode/blob/master/Java/"+ file.getName() +")| |" + "Java|\n";
- count++;
- }
- }
- return outputContent;
- }
-
- public static void printTable(String fileName, String outputContent) {
- System.out.println(outputContent);
- //Write to README.md
- try {
- File outFile = new File(fileName);
- FileOutputStream fop = new FileOutputStream(outFile);
- byte[] contentInBytes = outputContent.getBytes();
- fop.write(contentInBytes);
- fop.flush();
- fop.close();
- System.out.println("Mission Accomplished. Now go ahead and commit");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
+import java.io.*;
+import java.util.*;
+/*
+Used to generate table of contents.
+ - No args: generate GitHub table
+ - args == 'wordpress', generate WordPress table.
+ - args == 'review', generate Review Page
+ - args == 'all', genereate both table
+*/
+public class GenerateCodeTable {
+ private static final String NOT_AVAILABLE = "N/A";
+ /*
+ TableRow, used to hold table object and sort by date.
+ */
+ private static class TableRow {
+ private long date = 0;
+ private String fileName;
+ private String level;
+ private String tutorialLink;
+ private String note;
+ private List tags;
+
+ public TableRow(
+ long date,
+ String fileName,
+ String level,
+ String tutorialLink,
+ String note,
+ List tags) {
+ this.date = date;
+ this.fileName = fileName;
+ this.level = level;
+ this.tutorialLink = tutorialLink;
+ this.note = note;
+ this.tags = tags;
+ }
+
+ public long getDate() {
+ return this.date;
+ }
+
+ public String getFileName() {
+ return this.fileName;
+ }
+
+ public String getLevel() {
+ return this.level;
+ }
+
+ public String getTutorialLink() {
+ return this.tutorialLink;
+ }
+
+ public String getNote() {
+ return this.note;
+ }
+
+ public List getTags() {
+ return this.tags;
+ }
+
+ public String getTableComposedLine() {
+ return "|[" + this.fileName + "](https://github.com/awangdev/LintCode/blob/master/Java/" + fileName.replace(" ", "%20")
+ + ")|" + this.level + "|Java|" + this.tags + "|"+ this.tutorialLink + "|\n";
+ }
+ }
+
+ public final static String TUTORIAL_KEY_WORD = "tutorial:";
+ public final static String TAGS_KEY_WORD = "tags:";
+ public static void main(String[] args) {
+ GenerateCodeTable gct = new GenerateCodeTable();
+ //Read Java Solution Folder
+ File folder = new File("./Java");//"." = current path
+ if (!folder.exists() || !folder.isDirectory()) {
+ System.out.println("Check Directory:1");
+ return;
+ }
+ File[] listOfFiles = folder.listFiles();
+ if (listOfFiles == null) {
+ System.out.println("Check Directory:2");
+ return;
+ }
+
+ String outputContent = "";
+ File outFile;
+
+ if (args.length == 0){
+ outputContent = gct.generateREADME(listOfFiles);
+ gct.printTable("README.md", outputContent);
+ } else if (args != null && args[0].contains("wordpress")) {//Wordpress
+ outputContent = gct.generateWordPressPage(listOfFiles);
+ gct.printTable("WordPress.txt", outputContent);
+ } else if (args != null && args[0].contains("review")) {//Review Page
+ outputContent = gct.generateReviewPage(listOfFiles);
+ gct.printTable("ReviewPage.md", outputContent);
+ } else if (args != null && args[0].contains("tags")) {//Wordpress
+ outputContent = gct.generateTagREADME(listOfFiles);
+ gct.printTable("TagREADME.md", outputContent);
+ } else if (args != null && args[0].contains("all")) {
+ outputContent = gct.generateREADME(listOfFiles);
+ gct.printTable("README.md", outputContent);
+ //outputContent = generateWordPressPage(listOfFiles);
+ //printTable("WordPress.txt", outputContent);
+ outputContent = gct.generateReviewPage(listOfFiles);
+ gct.printTable("ReviewPage.md", outputContent);
+ outputContent = gct.generateTagREADME(listOfFiles);
+ gct.printTable("TagREADME.md", outputContent);
+ outputContent = gct.generateTagReviewPage(listOfFiles);
+ gct.printTable("TagReviewPage.md", outputContent);
+ outputContent = gct.generateLevelReviewPage(listOfFiles);
+ gct.printTable("LevelReviewPage.md", outputContent);
+ }
+
+ System.out.println("Mission Accomplished. Now go ahead and commit");
+ }
+
+ /*
+ Output the content into file
+ */
+ public void printTable(String fileName, String outputContent) {
+ //System.out.println(outputContent);
+ //Write to README.md
+ try {
+ File outFile = new File(fileName);
+ FileOutputStream fop = new FileOutputStream(outFile);
+ byte[] contentInBytes = outputContent.getBytes();
+ fop.write(contentInBytes);
+ fop.flush();
+ fop.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /*
+ Generate Wordpress contents
+ */
+ public String generateWordPressPage(File[] listOfFiles) {
+ //Assemble output
+ String outputContent = "Java Solutions to algorithm problems from LintCode, LeetCode...etc.\n" +
+ "" +
+ "" +
+ "" +
+ "# | " +
+ "Problem | " +
+ " Language | " +
+ "
" +
+ "" +
+ "";
+
+ int count = 0;
+ for (File file : listOfFiles) {
+ if (file.getName().contains(".java")) {
+ //outputContent += "|" + count + "|[" + file.getName() + "](https://github.com/awangdev/LintCode/blob/master/Java/"+ file.getName() +")| |" + "Java|\n";
+ outputContent+=
+ "" +
+ "" + count + " | " +
+ "" + file.getName() + " | " +
+ "Java | " +
+ "
";
+ count++;
+ }
+ }
+
+ outputContent += "
";
+ return outputContent;
+ }
+
+
+ /*
+ Generate GitHub ReadMe contents
+ */
+ public String generateREADME(File[] listOfFiles) {
+ //Assemble output
+ String outputContent = "# Java Algorithm Problems\n\n" +
+ "### 程序员的一天\n" +
+ "从开始这个Github已经有将近两年时间, 很高兴这个repo可以帮到有需要的人. 我一直认为, 知识本身是无价的, 因此每逢闲暇, 我就会来维护这个repo, 给刷题的朋友们一些我的想法和见解. 下面来简单介绍一下这个repo:\n\n" +
+ "**README.md**: 所有所做过的题目\n\n" +
+ "**ReviewPage.md**: 所有题目的总结和归纳(不断完善中)\n\n" +
+ "**KnowledgeHash2.md**: 对所做过的知识点的一些笔记\n\n" +
+ "**SystemDesign.md**: 对系统设计的一些笔记\n\n" +
+ "**Future Milestone**: 我准备将一些有意思的题目,做成视频的形式给大家参考\n\n" +
+ //"**借此机会, 正式介绍一下自己, 以及我背后的大老板**\n\n" +
+ //"[](https://youtu.be/3keMZsV1I1U)\n\n" +
+ "希望大家学习顺利, 对未来充满希望(程序员也是找到好老板的!)\n" +
+ "有问题可以给我写邮件(wangdeve@gmail.com), 或者在GitHub上发issue给我.\n\n" +
+ "| Squence | Problem | Level | Language | Tags | Video Tutorial|\n" +
+ "|:-------:|:--------------|:------:|:---------:|:----:|:-------------:|\n";
+ final List tableRows = getTableRows(listOfFiles);
+ for (int i = 0; i < tableRows.size(); i++) {
+ outputContent += "|" + i + tableRows.get(i).getTableComposedLine();
+ }
+ return outputContent;
+ }
+
+ /* Generate the tags Table*/
+ public String generateTagREADME(File[] listOfFiles) {
+ String outputContent = generateTableOfContent("TagREADME.md") + "\n\n";
+ String header = "| Squence | Problem | Level | Language | Tags | Video Tutorial|\n" +
+ "|:-------:|:--------------|:------:|:---------:|:----:|:-------------:|\n";
+ final List tableRows = getTableRows(listOfFiles);
+ final HashMap> tagToRows = new HashMap<>();
+ tableRows.forEach(tableRow -> {
+ for (String tag: tableRow.getTags()) {
+ if (tag == null || tag.length() == 0) {
+ continue;
+ }
+ if (!tagToRows.containsKey(tag)) {
+ tagToRows.put(tag, new ArrayList());
+ }
+ tagToRows.get(tag).add(tableRow);
+ }
+ });
+ // Build View
+ List>> entries = new ArrayList<>(tagToRows.entrySet());
+ entries.sort(Comparator.comparing(entry -> -entry.getValue().size()));
+
+ for (Map.Entry> entry : entries) {
+ StringBuffer sb = new StringBuffer(" \n \n \n## " + entry.getKey() + " (" + entry.getValue().size() + ")\n");
+ sb.append(header);
+ List entryTableRows = entry.getValue();
+ entryTableRows.sort(Comparator.comparing(row -> String.join(",", row.getTags())));
+ for (int i = 0; i < entryTableRows.size(); i++) {
+ sb.append("|" + i + entryTableRows.get(i).getTableComposedLine());
+ }
+ outputContent += sb.toString() + "\n\n\n";
+ }
+ return outputContent;
+ }
+
+ // Generate review files by tags
+ public String generateTagReviewPage(File[] listOfFiles) {
+ final List tableRows = getTableRows(listOfFiles);
+ final HashMap> tagToRows = new HashMap<>();
+ // Group by tags:
+ tableRows.forEach(tableRow -> {
+ for (String tag: tableRow.getTags()) {
+ if (tag == null || tag.length() == 0) {
+ continue;
+ }
+ if (!tagToRows.containsKey(tag)) {
+ tagToRows.put(tag, new ArrayList());
+ }
+ tagToRows.get(tag).add(tableRow);
+ }
+ });
+ // Build View
+ String outputContent = "";
+ for (Map.Entry> entry : tagToRows.entrySet()) {
+ StringBuffer sb = new StringBuffer(" \n \n \n## " + entry.getKey() + " (" + entry.getValue().size() + ")\n");
+ sb.append(buildReviewSection(entry.getValue()));
+ outputContent += sb.toString() + "\n\n\n";
+ printTable("review/" + entry.getKey() + ".md", sb.toString());
+ }
+ return outputContent;
+ }
+
+ // Generate review files by levels
+ public String generateLevelReviewPage(File[] listOfFiles) {
+ final List tableRows = getTableRows(listOfFiles);
+ final HashMap> levelToRows = new HashMap<>();
+ // Group by levels:
+ tableRows.forEach(tableRow -> {
+ String level = tableRow.getLevel();
+ if (NOT_AVAILABLE.equals(tableRow.getLevel())) {
+ level = "NA";
+ }
+ if (!levelToRows.containsKey(level)) {
+ levelToRows.put(level, new ArrayList());
+ }
+ levelToRows.get(level).add(tableRow);
+ });
+ // Build View
+ String outputContent = "";
+ for (Map.Entry> entry : levelToRows.entrySet()) {
+ StringBuffer sb = new StringBuffer(" \n \n \n## " + entry.getKey() + " (" + entry.getValue().size() + ")\n");
+ sb.append(buildReviewSection(entry.getValue()));
+ outputContent += sb.toString() + "\n\n\n";
+ printTable("review/level/" + entry.getKey() + ".md", sb.toString());
+ }
+ return outputContent;
+ }
+
+ /*
+ Generate Review Page contents
+ Review Page content:
+ 1. Sequence
+ 2. Name
+ 3. Difficulty
+ 4. Summary of solution, key points.
+ */
+ public String generateReviewPage(File[] listOfFiles) {
+ //Assemble output
+ String outputContent = "# Review Page\n\n" +
+ "This page summarize the solutions of all problems. For thoughts,ideas written in English, refer to deach individual solution. \n" +
+ "New problems will be automatically updated once added.\n\n";
+
+ final List tableRows = getTableRows(listOfFiles);
+ int count = 0;
+ int countMiss = 0;
+ outputContent += buildReviewSection(tableRows);
+ return outputContent;
+ }
+
+ private String buildReviewSection(List tableRows) {
+ int count = 0;
+ int countMiss = 0;
+ StringBuffer sb = new StringBuffer();
+ for (TableRow tableRow: tableRows) {
+ // Skip non-ready items
+ if (NOT_AVAILABLE.equals(tableRow.getLevel())) {
+ System.out.println(countMiss + ". [File not yet formatted]: " + tableRow.getFileName() + " [Skipping. Please revisit]");
+ countMiss++;
+ continue;
+ }
+ //System.out.println(count + ". " + tableRow.getLevel() + " [File not yet formatted]: " + tableRow.getFileName());
+ sb.append("**" + count + ". [" + tableRow.getFileName());
+ sb.append("](https://github.com/awangdev/LintCode/blob/master/Java/");
+ sb.append(tableRow.getFileName().replace(" ", "%20") +")**");
+
+ sb.append(" Level: " + tableRow.getLevel() + " Tags: " + tableRow.getTags() + "\n");
+ sb.append(" " + tableRow.getTutorialLink() + "\n");
+ sb.append(tableRow.getNote() + "\n");
+ sb.append("\n---\n\n");
+ count++;
+ }
+ return sb.toString();
+ }
+
+
+
+ private List getTableRows(File[] listOfFiles) {
+ final ArrayList tableRows = new ArrayList<>();
+ for (File file : listOfFiles) {
+ if (file.getName().contains(".java")) {
+ tableRows.add(getTableRow(file.getName()));
+ }
+ }
+ Collections.sort(tableRows, Comparator.comparing(TableRow::getDate));
+ return tableRows;
+ }
+
+ private TableRow getTableRow(String fileName) {
+ TableRow tableRow = null;
+ String tutorialLink = "";
+ String calculatedLevel = NOT_AVAILABLE;
+ long timestamp = 0;
+ List tags = new ArrayList<>();
+ try {
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(
+ new FileInputStream("Java/" + fileName), "UTF-8"));
+ // Get level
+ String line = reader.readLine().trim();
+ if (line.length() == 1 && !calculateLevel(line).isEmpty()){
+ calculatedLevel = calculateLevel(line.toUpperCase());
+ line = reader.readLine().trim();
+ }
+
+ // Get timestamp
+ if (line.length() != 0) {
+ try{
+ timestamp = Long.parseLong(line);
+ line = reader.readLine().trim();
+ }catch(final Exception e){
+ System.out.println("Timestamp Not added yet: " + fileName);
+ }
+ }
+
+ // Get tutorial
+ if (line.contains(TUTORIAL_KEY_WORD)) {
+ tutorialLink = "[Link](" + line.substring(TUTORIAL_KEY_WORD.length()) + ")";
+ line = reader.readLine().trim();
+ }
+
+ // Get Tags
+ if (line.contains(TAGS_KEY_WORD)) {
+ // Do something
+ String tagLine = line.substring(TAGS_KEY_WORD.length());
+ for (String tag : tagLine.split(",")) {
+ tags.add(tag.trim());
+ }
+ Collections.sort(tags);
+ }
+
+ // Get Note
+ String note = "";
+ while ((line = reader.readLine()) != null && !line.equals("```") && !line.equals("/*")) {
+ note += line + "\n";
+ }
+
+ // Get result
+ tableRow = new TableRow(timestamp, fileName, calculatedLevel, tutorialLink, note, tags);
+ } catch (final Exception e) {
+ System.err.format("IOException: %s%n", e);
+ }
+ return tableRow;
+ }
+
+ private String calculateLevel(final String level) {
+ switch(level) {
+ case "N" :
+ return "Naive";
+ case "E" :
+ return "Easy";
+ case "M" :
+ return "Medium";
+ case "H" :
+ return "Hard";
+ case "S" :
+ return "Super";
+ case "R" :
+ return "Review";
+ }
+ return NOT_AVAILABLE;
+ }
+
+ // Build the table of contents of the page. Need to have 'gh-md-toc' installed
+ private String generateTableOfContent(String fileName) {
+ StringBuffer sb = new StringBuffer();
+ try {
+ Runtime rt = Runtime.getRuntime();
+ String[] commands = {"./gh-md-toc", fileName};
+ Process proc = rt.exec(commands);
+
+ BufferedReader stdInput = new BufferedReader(new
+ InputStreamReader(proc.getInputStream()));
+
+ BufferedReader stdError = new BufferedReader(new
+ InputStreamReader(proc.getErrorStream()));
+
+ // read the output from the command
+ System.out.println("Here is the standard output of the command:\n");
+ String s = null;
+ while ((s = stdInput.readLine()) != null) {
+ if (!s.contains("[gh-md-toc]") && !s.contains("table-of-contents")) {
+ sb.append(s.trim() + "\n");
+ }
+ }
+
+ // read any errors from the attempted command
+ System.out.println("Here is the standard error of the command (if any):\n");
+ while ((s = stdError.readLine()) != null) {
+ System.out.println(s);
+ }
+ } catch (final Exception e) {
+ System.err.format("IOException: %s%n", e);
+ }
+ System.out.println(sb.toString());
+ return sb.toString();
+ }
}
\ No newline at end of file
diff --git a/Java/1-bit and 2-bit Characters.java b/Java/1-bit and 2-bit Characters.java
new file mode 100644
index 0000000..f7977e9
--- /dev/null
+++ b/Java/1-bit and 2-bit Characters.java
@@ -0,0 +1,95 @@
+E
+1517474043
+tags: Array
+
+方法1:
+Greedy.
+从第一个bit开始数: 如果遇到1, 一定是跳两位;如果遇到0, 一定是跳一位.
+loop to end, and see if index reaches the end.
+
+方法2:
+用DP硬做了一下:
+1. 如果i位是0, 那么前面dp[i-1]或者dp[i-2] true就够了.
+2. 如果i位是1, 那么i-1位必须是1才满足规则, 并且 dp[i-2]需要true.
+
+```
+/*
+We have two special characters. The first character can be represented by one bit 0. The second character can be represented by two bits (10 or 11).
+
+Now given a string represented by several bits. Return whether the last character must be a one-bit character or not. The given string will always end with a zero.
+
+Example 1:
+Input:
+bits = [1, 0, 0]
+Output: True
+Explanation:
+The only way to decode it is two-bit character and one-bit character. So the last character is one-bit character.
+Example 2:
+Input:
+bits = [1, 1, 1, 0]
+Output: False
+Explanation:
+The only way to decode it is two-bit character and two-bit character. So the last character is NOT one-bit character.
+Note:
+
+1 <= len(bits) <= 1000.
+bits[i] is always 0 or 1.
+*/
+/*
+Thoughts:
+Greedy.
+从第一个bit开始数: 如果遇到1, 一定是跳两位;如果遇到0, 一定是跳一位.
+loop to end, and see if index reaches the end.
+*/
+class Solution {
+ public boolean isOneBitCharacter(int[] bits) {
+ if (bits == null || bits.length == 0) {
+ return false;
+ }
+ int index = 0;
+ while (index < bits.length - 1) {
+ index += bits[index] % 2 == 1 ? 2 : 1;
+ }
+ return index == bits.length - 1;
+ }
+}
+
+/*
+Thoughts:
+check if last bit must be '0': check can it be decoded if not single-bit-0 ending?
+Should check if bits with less 2 bits still valid?
+DP.
+dp[i]: can be decoded at i
+we only actaully need to know up to dp[i - 1]
+
+if bits[i] == 0: dp[i] = dp[i - 2] || dp[i - 1];
+if bits[i] == 1: dp[i] = dp[i - 2] && bits[i - 1] == 1;
+
+*/
+class Solution {
+ public boolean isOneBitCharacter(int[] bits) {
+ if (bits == null || bits.length == 0) {
+ return false;
+ }
+ int n = bits.length;
+ if (n == 1) {
+ return bits[0] == 0;
+ }
+ if (bits[n - 1] != 0) {
+ return false;
+ }
+
+ boolean[] dp = new boolean[n];
+ dp[0] = bits[0] == 0;
+ dp[1] = bits[0] != 0 || bits[1] != 1;
+ for (int i = 2; i < n - 1; i++) {
+ if (bits[i] == 0) {
+ dp[i] = dp[i - 2] || dp[i - 1];
+ } else if (bits[i] == 1) {
+ dp[i] = dp[i - 2] && bits[i - 1] == 1;
+ }
+ }
+ return dp[n - 2];
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/2 Sum II.java b/Java/2 Sum II.java
new file mode 100755
index 0000000..8daceb4
--- /dev/null
+++ b/Java/2 Sum II.java
@@ -0,0 +1,126 @@
+M
+1516439472
+tags: Array, Two Pointers, Binary Search
+
+与 2sum II - input array is sorted类似. 都是sort array, 然后two pointer.
+
+LintCode的题. 注意找的是greater/bigger than target。
+
+由于给定条件允许O(nLogn):
+ sort
+ two pointer
+
+while里面two pointer移动。每次如果num[left]+num[right] > target,那么其中所有num[left++]的加上num[right]都>target.
+也就是,num[right]不动,计算加入挪动left能有多少组,那就是: right-left这么多。 全部加到count上去。
+然后right--.换个right去和前面的left部分作比较。
+
+```
+/*
+Given an array of integers, find how many pairs in the array such that
+their sum is bigger than a specific target number. Please return the number of pairs.
+Example
+numbers=[2, 7, 11, 15], target=24
+
+return 1
+
+Challenge
+Either of the following solutions are acceptable:
+
+O(1) Space, O(nlogn) Time
+Tags Expand
+Two Pointers
+
+*/
+
+/*
+Thoughts:
+After doing Trigle Count...Can we just do the same for this, move while pointers to center?
+OMG. The original idea was sooooooo complicated.
+*/
+public class Solution {
+ public int twoSum2(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int count = 0;
+ int left = 0;
+ int right = nums.length - 1;
+ Arrays.sort(nums);
+ while (left < right) {
+ if (nums[left] + nums[right] > target) {
+ count += (right - left);
+ right--;
+ } else {
+ left++;
+ }
+ }
+ return count;
+ }
+}
+
+//Below are bad solutions. Don't worry about them
+
+/*
+
+Thoughts:
+1. For loop to try each element from (i ~ end). O(n)
+2. In for, do binary search on nums[i] + nums[j] > target,
+3. count += (length - j)
+
+Note: when not found, return nums.length, because at then end, (length - length) == 0, which will be added to count.
+Note: Always pin target down, and move mid to compare. Don't get confused
+Also, take care of corner cases.
+*/
+
+public class Solution {
+ public int twoSum2(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int count = 0;
+ Arrays.sort(nums);
+ for (int i = 1; i < nums.length; i++) {
+ int index = binarySearch(nums, target - nums[i - 1], i, nums.length - 1);
+ count += nums.length - index;
+ }
+ return count;
+ }
+
+ public int binarySearch(int[] nums, int target, int start, int end) {
+ int mid;
+ int sum;
+ while (start + 1 < end) {
+ mid = start + (end - start) /2;
+ if (mid - 1 >= 0 && nums[mid-1] <= target && target < nums[mid]) {
+ return mid;
+ } else if (mid + 1 < nums.length && nums[mid] <= target && target < nums[mid + 1]) {
+ return mid + 1;
+ } else if (target < nums[mid]) {
+ end = mid;
+ } else {
+ start = mid;
+ }
+ }
+ if (nums[start] > target) {
+ return start;
+ }
+ return (nums[end] > target) ? end : nums.length;
+ }
+}
+
+//Brutle force, O(n^2)
+public class Solution {
+ public int twoSum2(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int count = 0;
+ for (int i = 0; i < nums.length - 1; i++) {
+ for (int j = i + 1; j < nums.length; j++) {
+ count += (nums[i] + nums[j] > target) ? 1 : 0;
+ }
+ }
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/2 Sum.java b/Java/2 Sum.java
deleted file mode 100644
index 06fea20..0000000
--- a/Java/2 Sum.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-Given an array of integers, find two numbers such that they add up to a specific target number.
-
-The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
-
-Note
-You may assume that each input would have exactly one solution
-
-Example
-numbers=[2, 7, 11, 15], target=9
-
-return [1, 2]
-
-Challenge
-1. O(1) Space, O(nlogn) Time
-
-2. O(n) Space, O(n) Time
-
-Tags Expand
-Array Two Pointers
-
-
-Using a HashMap, O(n) space and O(n) time.
-Thinking process:
-Push everything into a HashMap.
-Check if one element exist in the HashMap, if so save it. Meanwhile, save the other one.
-Trick: after adding into the HashMap, we are looking for the 2nd index first. This is particularly because the way we write the code in optimized form:
- always check (target - current) from the HashMap. If exist, that means index0 has already been pushed into the HashMap and current value is at index1.
-(key, value) = (numbers[i], i)
-Note: return index+1 because this is not 0-based.
-*/
-
-public class Solution {
- /*
- * @param numbers : An array of Integer
- * @param target : target = numbers[index1] + numbers[index2]
- * @return : [index1 + 1, index2 + 1] (index1 < index2)
- */
- //Using HashMap
- public int[] twoSum(int[] numbers, int target) {
- if (numbers == null || numbers.length == 0) {
- return null;
- }
- int[] rst = new int[2];
- HashMap map = new HashMap();
- for (int i = 0; i < numbers.length; i++) {
- if (map.containsKey(target - numbers[i])) {
- rst[0] = map.get(target - numbers[i]) + 1;
- rst[1] = i + 1;
- } else {
- map.put(numbers[i], i);
- }
- }
- return rst;
- }
-}
-
-
-
-//2. O(1) Space O(nlogn) time
-//TODO
-
diff --git a/Java/3 Sum Closest.java b/Java/3 Sum Closest.java
old mode 100644
new mode 100755
index ea4b234..317ca21
--- a/Java/3 Sum Closest.java
+++ b/Java/3 Sum Closest.java
@@ -1,51 +1,65 @@
-/*
-Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers.
+M
+1516610949
+tags: Array, Two Pointers
+
+3Sum 的一种简单形式, 并且都没有找index, value, 而只是找个sum罢了.
+
+double for loop。 2Sum只能用土办法 left/right 2 pointers。 O(n^2)
+
+注意:check closest时候用long, 以免int不够用
+```
+/*
+Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target.
+Return the sum of the three integers.
Note
You may assume that each input would have exactly one solution.
-
Example
For example, given array S = {-1 2 1 -4}, and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
-
Tags Expand
Two Pointers Sort Array
-Thinking process:
-Similar to 3 SUM.
-Starting from the left-element, assume it's the solution. Move the 2 pointers in the right-side-array.
-Using the two pointers, trying to find ele1 + ele2 + ele3 = closest number to target.
-Note: for comparing closet, use initial value Integer.MAX_VALUE. Be aware of the overflow of integer, use long to handle.
*/
-public class Solution {
- /**
- * @param numbers: Give an array numbers of n integer
- * @param target : An integer
- * @return : return the sum of the three integers, the sum closest target.
- */
- public int threeSumClosest(int[] num, int target) {
- if (num == null || num.length < 3) {
- return Integer.MAX_VALUE;
+/*
+Thoughts:
+3 SUM = for loop + 2SUM. Normally it'd be O(n^2).
+Two pointer in the inner 2SUM..
+Note: result should be initialized with first 3 indexes.
+*/
+class Solution {
+ public int threeSumClosest(int[] nums, int target) {
+ if (nums == null || nums.length < 3) {
+ return 0;
}
- Arrays.sort(num);
- long closest = (long) Integer.MAX_VALUE;
- for (int i = 0; i < num.length - 2; i++) {
- int left = i + 1;
- int right = num.length - 1;
- while (left < right) {
- int sum = num[i] + num[left] + num[right];
- if (sum == target) {
- return sum;
- } else if (sum < target) {
- left++;
+ Arrays.sort(nums); // nLog(n)
+ long result = nums[0] + nums[1] + nums[2];
+ for (int i = 0; i < nums.length - 2; i++) {
+ int start = i + 1;
+ int end = nums.length - 1;
+ while (start < end) {
+ long sum = nums[start] + nums[end] + nums[i];
+ if (sum > target) {
+ end--;
} else {
- right--;
+ start++;
}
- closest = Math.abs(sum - target) < Math.abs(closest - target)
- ? (long) sum : closest;
- }//while
- }//for
- return (int) closest;
+ result = Math.abs(sum - target) < Math.abs(result - target) ? sum : result;
+ }
+ }
+ return (int)result;
}
}
+
+
+/*
+Previous notes
+Thoughts:
+ Similar to 3 SUM.
+ Starting from the left-element, assume it's the solution. Move the 2 pointers in the right-side-array.
+ Using the two pointers, trying to find ele1 + ele2 + ele3 = closest number to target.
+ Note: for comparing closet, use initial value Integer.MAX_VALUE. Be aware of the overflow of integer, use long to handle.
+
+*/
+```
\ No newline at end of file
diff --git a/Java/3 Sum.java b/Java/3 Sum.java
deleted file mode 100644
index df0a63e..0000000
--- a/Java/3 Sum.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
-
-Note
-Elements in a triplet (a,b,c) must be in non-descending order. (ie, a = b = c)
-
-The solution set must not contain duplicate triplets.
-
-Example
-For example, given array S = {-1 0 1 2 -1 -4}, A solution set is:
-
-(-1, 0, 1)
-
-(-1, -1, 2)
-
-Tags Expand
-Two Pointers Sort Array
-
-Thinking process:
-Cannot use HashMap for this problem because of the duplicates. See the bottom of this file for the failed version.
-Remember to check for null and edge-soluton.
-Before everything, Arrays.sort() the given array, in order to effectively handle the duplicates.
-At 3SUM level, takes 1 element out and do 2SUM on the rest of the front elements of the array. Note, 2SUM has multitple solutions (need to handle duplicates)
-Cross-match the 2SUM solution with the selected element from 3SUM level.
-*/
-
-
-public class Solution {
- /**
- * @param numbers : Give an array numbers of n integer
- * @return : Find all unique triplets in the array which gives the sum of zero.
- */
- public ArrayList> threeSum(int[] numbers) {
- ArrayList> rst = new ArrayList>();
- if (numbers == null && numbers.length <= 2) {// Length at least >= 3
- return rst;
- }
- Arrays.sort(numbers);//Sort in order to handle duplicates
- for (int i = numbers.length - 1; i >= 2; i--) {// i >=2 because at least 3 element in result.
- if (i < numbers.length - 1 && numbers[i] == numbers[i + 1]) {
- continue;//The case of numbers[i + 1] should have already covered all possibilities of the case numbers[i], so safe to skip
- }
- ArrayList> twoSum = calTwoSum(numbers, i - 1, 0 - numbers[i]);//Pick the 3rd element numbers[i]
- for (int j = 0; j < twoSum.size(); j++) {//Find two sum of rest-front elements. Cross add them with numbers[i]
- twoSum.get(j).add(numbers[i]);
- }
- rst.addAll(twoSum);
- }
- return rst;
- }
- //Two Sum. Multiple answer
- public ArrayList> calTwoSum(int[] num, int end, int target) {
- ArrayList> rst = new ArrayList>();
- if (num == null || num.length <= 1) {//Length at least >= 2
- return rst;
- }
- int left = 0;
- int right = end;
- while (left < right) {
- if (num[left] + num[right] == target) {
- ArrayList match = new ArrayList();
- match.add(num[left]);
- match.add(num[right]);
- rst.add(match);
- left++;
- right--;
- //For unique number A, there is only 1 unique number B such that A + B == target.
- //Therefore, once found the match, erase all numbers that's equal to A or equal to B
- while (left < right && num[left] == num[left - 1]) {
- left++;
- }
- while (left < right && num[right] == num[right + 1]) {
- right--;
- }
- } else if (num[left] + num[right] < target) {//Since int[] num is sorted: move L to right-side to get larger value.
- left++;
- } else {
- right--;
- }
- }
- return rst;
- }
-}
-
-
-
-
-
-
-
-/*
-The following is a exceeding time version.
-I believe the concept is clear, but it does not handle duplicates well. So we can't use this version.
-
-
-public class Solution {
- public ArrayList> threeSum(int[] numbers) {
- ArrayList> rst = new ArrayList>();
- if (numbers.length <= 2) {
- return rst;
- }
- Arrays.sort(numbers);
- for (int i = 0; i < numbers.length; i++){
- HashMap map = new HashMap();
- for (int j = i; j < numbers.length; j++) {
- int remain = 0 - numbers[i] - numbers[j];
- if (map.containsKey(remain) && map.get(remain) != i) {
- ArrayList list = new ArrayList();
- list.add(numbers[i]);
- list.add(remain);
- list.add(numbers[j]);
- if (!rst.contains(list)){
- rst.add(list);
- }
- } else {
- map.put(numbers[j], j);
- }
- }
- }
- return rst;
- }
-}
-
-*/
\ No newline at end of file
diff --git a/Java/3Sum Smaller.java b/Java/3Sum Smaller.java
new file mode 100755
index 0000000..6efb30f
--- /dev/null
+++ b/Java/3Sum Smaller.java
@@ -0,0 +1,91 @@
+M
+1517465602
+tags: Two Pointers, Array
+
+一般的O(n3)肯定不行。在此基础上优化。
+发现j,k满足条件时候,(k - j)就是所有 sum target, 又因为j不能后退,只能k--,那么问题就被锁定了. 这样可以做到O(n2)
+
+```
+/*
+Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < n
+that satisfy the condition nums[i] + nums[j] + nums[k] < target.
+
+For example, given nums = [-2, 0, 1, 3], and target = 2.
+
+Return 2. Because there are two triplets which sums are less than 2:
+
+[-2, 0, 1]
+[-2, 0, 3]
+
+Follow up:
+Could you solve it in O(n2) runtime?
+
+Tags: Array Two Pointers
+Similar Problems:(M) 3Sum, (M) 3Sum Closest
+
+*/
+
+/*
+Thoughts:
+For loop over initial selection. Have 2sum solution within (2 pointer).
+When < target, count+= end-start, start++.
+When >= target, end--.
+*/
+class Solution {
+ public int threeSumSmaller(int[] nums, int target) {
+ if (nums == null || nums.length <= 2) {
+ return 0;
+ }
+ Arrays.sort(nums);
+ int count = 0;
+ for (int i = 0; i < nums.length - 2; i++) { // first num, num[i] is the fixed item
+ int start = i + 1, end = nums.length - 1; // move start, end
+ while (start < end) {
+ if (nums[i] + nums[start] + nums[end] < target) {
+ count += end - start;
+ start++;
+ } else {
+ end--;
+ }
+ }
+ }
+ return count;
+ }
+}
+
+/*
+Thoughts:
+Similar to 3 sum, but ofcourse, this one check on '<' so we can not use HashMap anymore.
+Basic concept is to fix first number, then check for the rest two numbers, see if they addup < target.
+When checking j and k, realize something nice:
+ if nums[j] + nums[k] < target - nums[i], that means for all index <= k will work, so directly add (k - j) to result (that's: index = j+1, j+2, ....,k)
+ also, move j forward for next round.
+OR, if three-add-up >= target, since j can only increase, we do k-- to make the three-add-up smaller
+
+Note:
+Don't forget to sort, otherwise the sequence/order is unpredictable
+*/
+public class Solution {
+ public int threeSumSmaller(int[] nums, int target) {
+ if (nums == null || nums.length <= 2) {
+ return 0;
+ }
+ Arrays.sort(nums);
+ int rst = 0;
+ for (int i = 0; i < nums.length - 2; i++) {
+ int j = i + 1;
+ int k = nums.length - 1;
+ while (j < k) {
+ if (nums[i] + nums[j] + nums[k] >= target) {
+ k--;
+ } else {
+ rst += (k - j);
+ j++;
+ }
+ }
+ }//END for
+ return rst;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/3Sum.java b/Java/3Sum.java
new file mode 100755
index 0000000..c6447b0
--- /dev/null
+++ b/Java/3Sum.java
@@ -0,0 +1,257 @@
+M
+1516689562
+tags: Array, Two Pointers
+
+
+#### sort array, for loop + two pointer. O(n^2)
+- 处理duplicate wthin triplets:
+- 如果最外圈的移动点i重复, 一直顺到结尾的最后一个再用.
+- 如果是triplet内有重复, 用完start point, 移动到结尾.
+
+Previous notes:
+注意:
+ 1. 找 value triplets, 多个结果。注意,并非找index。
+ 2. 要升序, 第一层for loop 从最后一个元素挑起, 保证了顺序。
+ 3. 去掉duplicate: check用过的同样的数字,都跳掉。不需要用同样的数字再计算一边已有结果。
+
+步骤:
+ 1. For loop 挑个数字A.
+ 2. 2Sum 出一堆2个数字的结果
+ 3. Cross match 步骤1里面的A.
+
+时间 O(n^2), 两个nested loop
+
+另外, 还是可以用HashMap来做2Sum。稍微短点。还是要注意handle duplicates.
+
+
+```
+/*
+Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0?
+Find all unique triplets in the array which gives the sum of zero.
+
+Example
+For example, given array S = {-1 0 1 2 -1 -4}, A solution set is:
+
+(-1, 0, 1)
+(-1, -1, 2)
+Note
+Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
+
+The solution set must not contain duplicate triplets.
+
+Tags Expand
+Two Pointers Sort Array Facebook
+*//*
+Thoughts:
+Sort the list, do a for loop and two pointer within.
+Make sure to skip duplicated index value:
+when 'start' is duplicated, start++ until no duplicates.
+when i is duplicated, continue in for loop and get to end of last duplicate and use that as i.
+
+O(n) * O(n) -> O(n^2)
+*/
+class Solution {
+ public List> threeSum(int[] nums) {
+ List> result = new ArrayList<>();
+ if (nums == null || nums.length == 0) {
+ return result;
+ }
+ Arrays.sort(nums);
+ for (int i = 2; i < nums.length; i++) {
+ if (i + 1 < nums.length && nums[i] == nums[i + 1]) {
+ continue;
+ }
+ int start = 0;
+ int end = i - 1;
+ while (start < end) {
+ if (nums[start] + nums[end] + nums[i] == 0) {
+ result.add(Arrays.asList(nums[start], nums[end], nums[i]));
+ start++;
+ while (start < end && nums[start - 1] == nums[start]) { // skip duplicates
+ start++;
+ }
+ } else if (nums[start] + nums[end] + nums[i] < 0) {
+ start++;
+ } else {
+ end--;
+ }
+ }
+ }
+ return result;
+ }
+}
+
+/*
+Thoughts:
+ Remember to check for null and edge-soluton.
+ Before everything, Arrays.sort() the given array, in order to effectively handle the duplicates.
+ At 3SUM level, takes 1 element out and do 2SUM on the rest of the front elements of the array. Note, 2SUM has multitple solutions (need to handle duplicates)
+ Cross-match the 2SUM solution with the selected element from 3SUM level.
+*/
+
+public class Solution {
+ public ArrayList> threeSum(int[] numbers) {
+ ArrayList> rst = new ArrayList>();
+ if (numbers == null && numbers.length <= 2) {// Length at least >= 3
+ return rst;
+ }
+ Arrays.sort(numbers);//Sort in order to handle duplicates
+ for (int i = numbers.length - 1; i >= 2; i--) {// i >=2 because at least 3 element in result; starting from end, ensures non-descending order
+ if (i < numbers.length - 1 && numbers[i] == numbers[i + 1]) {
+ continue;//The case of numbers[i + 1]: should have already covered all possibilities of the case numbers[i], so safe to skip
+ }
+ ArrayList> twoSum = calTwoSum(numbers, i - 1, 0 - numbers[i]);//Pick the 3rd element numbers[i]
+ for (int j = 0; j < twoSum.size(); j++) {//Find two sum of rest-front elements. Cross add them with numbers[i]
+ twoSum.get(j).add(numbers[i]);
+ }
+ rst.addAll(twoSum);
+ }
+ return rst;
+ }
+ //Two Sum. Multiple answer
+ public ArrayList> calTwoSum(int[] num, int end, int target) {
+ ArrayList> rst = new ArrayList>();
+ int left = 0;
+ int right = end;
+ while (left < right) {
+ if (num[left] + num[right] == target) {
+ ArrayList match = new ArrayList();
+ match.add(num[left]);
+ match.add(num[right]);
+ rst.add(match);
+ left++;
+ right--;
+ //For unique number A, there is only 1 unique number B such that A + B == target.
+ //Therefore, once found the match, erase all numbers that's equal to A or equal to B
+ while (left < right && num[left] == num[left - 1]) {
+ left++;
+ }
+ while (left < right && num[right] == num[right + 1]) {
+ right--;
+ }
+ } else if (num[left] + num[right] < target) {//Since int[] num is sorted: move L to right-side to get larger value.
+ left++;
+ } else {
+ right--;
+ }
+ }
+ return rst;
+ }
+}
+
+
+/*
+ Thoughts:
+ Exact same approach, except using HashMap in 2Sum
+*/
+//With HashMap 2Sum
+public class Solution {
+ public ArrayList> threeSum(int[] numbers) {
+ ArrayList> rst = new ArrayList>();
+ if (numbers == null && numbers.length <= 2) {// Length at least >= 3
+ return rst;
+ }
+ Arrays.sort(numbers);//Sort in order to handle duplicates
+ for (int i = numbers.length - 1; i >= 2; i--) {// i >=2 because at least 3 element in result; starting from end, ensures non-descending order
+ if (i < numbers.length - 1 && numbers[i] == numbers[i + 1]) {
+ continue;//The case of numbers[i + 1]: should have already covered all possibilities of the case numbers[i], so safe to skip
+ }
+ ArrayList> twoSum = calTwoSum(numbers, i - 1, 0 - numbers[i]);//Pick the 3rd element numbers[i]
+ for (int j = 0; j < twoSum.size(); j++) {//Find two sum of rest-front elements. Cross add them with numbers[i]
+ twoSum.get(j).add(numbers[i]);
+ }
+ rst.addAll(twoSum);
+ }
+ return rst;
+ }
+ //Two Sum. Multiple answer, with HashMap
+ public ArrayList> calTwoSum(int[] num, int end, int target) {
+ ArrayList> rst = new ArrayList>();
+ ArrayList match;
+ HashMap map = new HashMap();
+ for (int i = 0; i <= end; i++) {
+ if (map.containsKey(num[i])) {
+ match = new ArrayList();
+ match.add(num[map.get(num[i])]);
+ match.add(num[i]);
+ if (!rst.contains(match)) {
+ rst.add(new ArrayList(match));
+ }
+ } else {
+ map.put(target - num[i], i);
+ }
+ //Skip duplicate
+ if (i < end && num[i] == num[i + 1]) {
+ continue;
+ }
+ }
+ return rst;
+ }
+}
+
+
+/*
+ From LeetCode Solution
+ Thoughts:
+ sort list. O(nLogn)
+ end: n^2
+ for (i = 0 ~ n) {
+ int target = 0 - nums[i];
+ while (start + 1 < end) {
+ start + end == target {
+ rst.add(i, star, end);
+ keep looking: start ++, end--
+ }
+ else start + end < target?
+ start++
+ else
+ end--;
+ }
+ }
+ }
+
+Note:
+ Check duplicates. Compute a unique string to savei set
+*/
+
+public class Solution {
+ public List> threeSum(int[] nums) {
+ List> rst = new ArrayList>();
+ if (nums == null || nums.length == 0) {
+ return rst;
+ }
+
+ Arrays.sort(nums);
+ HashSet set = new HashSet();
+ //use old target to check duplicates. instead of set.
+ for (int i = 0; i < nums.length - 2; i++) {
+ int target = 0 - nums[i];
+ int start = i + 1;
+ int end = nums.length - 1;
+
+ ArrayList list = new ArrayList();
+ while (start < end) {
+ if (nums[start] + nums[end] == target &&
+ !set.contains(nums[i] + "," + nums[start] + "," + nums[end])) {
+ list.add(nums[i]);
+ list.add(nums[start]);
+ list.add(nums[end]);
+ rst.add(list);
+ set.add(nums[i] + "," + nums[start] + "," + nums[end]);
+ list = new ArrayList();
+ start++;
+ end--;
+ } else if (nums[start] + nums[end] < target) {
+ start++;
+ } else {
+ end--;
+ }
+ }//end while
+ }
+
+ return rst;
+ }
+}
+
+
+```
\ No newline at end of file
diff --git a/Java/4 Sum.java b/Java/4 Sum.java
deleted file mode 100644
index 7426ba2..0000000
--- a/Java/4 Sum.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
-
-Example
-For example, given array S = {1 0 -1 0 -2 2}, and target = 0. A solution set is:
-
-(-1, 0, 0, 1)
-
-(-2, -1, 1, 2)
-
-(-2, 0, 0, 2)
-
-Note
-Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
-
-The solution set must not contain duplicate quadruplets.
-
-Tags Expand
-Two Pointers Sort Hash Table Array
-
-Thinking process:
-Perform another layer outsideo of 3SUM.
-
-Note: If try to divide and perform two 2SUM, it will be a bit difficult. Refer to http://blog.csdn.net/linhuanmars/article/details/24826871
-*/
-
-public class Solution {
- /**
- * @param numbers : Give an array numbersbers of n integer
- * @param target : you need to find four elements that's sum of target
- * @return : Find all unique quadruplets in the array which gives the sum of
- * zero.
- */
- public ArrayList> fourSum(int[] numbers, int target) {
- ArrayList> rst = new ArrayList>();
- if(numbers == null || numbers.length < 4) {
- return rst;
- }
- Arrays.sort(numbers);
- //Pick 1st element
- for (int i = 0; i < numbers.length - 3; i++) {
- if (i != 0 && numbers[i] == numbers[i - 1]) {//Check for duplicate of 1st element
- continue;
- }
- //Pick 2nd element
- for (int j = i + 1; j < numbers.length - 2; j++) {
- if (j != i + 1 && numbers[j] == numbers[j - 1]) {//Check for duplicate of 2nd element
- continue;
- }
- //Pick 3rd and 4th element
- int third = j + 1;
- int fourth = numbers.length - 1;
- while (third < fourth) {
- int sum = numbers[i] + numbers[j] + numbers[third] + numbers[fourth];
- if (sum < target) {
- third++;
- } else if (sum > target) {
- fourth--;
- } else {//sum == target
- ArrayList list = new ArrayList();
- list.add(numbers[i]);
- list.add(numbers[j]);
- list.add(numbers[third]);
- list.add(numbers[fourth]);
- rst.add(list);
- third++;
- fourth--;
- while (third < fourth && numbers[third] == numbers[third - 1]) {
- third++;
- }
- while (third < fourth && numbers[fourth] == numbers[fourth + 1]){
- fourth--;
- }
- }
- }
- }
- }
- return rst;
- }
-}
-
diff --git a/Java/4Sum.java b/Java/4Sum.java
new file mode 100755
index 0000000..0d15e7e
--- /dev/null
+++ b/Java/4Sum.java
@@ -0,0 +1,228 @@
+M
+1533626601
+tags: Hash Table
+
+#### Based on 2sum
+- 1. 利用2Sum的原理,把4Sum分为连个2Sum。左一个pair,右一个pair,每个pair里面放2个数字。
+- 2. 以一个点,i,作为分界口,也要列举出所有i之前的pair,作为基础。
+- 3. 再尝试从所有i+1后面,找合适的2nd pair。
+- Time: O(n^2 * x), where x = # of candidates, still slow
+- 可以用HashSet, 可以直接比较list里面每一个元素, 保证set不重复.
+- Previous Notes: 在造class Pair时候,要做@override的function: hashCode(), equals(Object d). 平时不太想得起来用。
+- 参见 http://lifexplorer.me/leetcode-3sum-4sum-and-k-sum/
+
+#### Based on 3Sum
+- 3Sum外面再加一层. 参考3Sum. 时间O(n^3)。 但此方法在k-sum时候,无疑过于费时间. O(n^k)
+
+```
+/*
+Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target?
+
+Find all unique quadruplets in the array which gives the sum of target.
+
+Example
+Given array S = {1 0 -1 0 -2 2}, and target = 0. A solution set is:
+
+(-1, 0, 0, 1)
+(-2, -1, 1, 2)
+(-2, 0, 0, 2)
+Note
+Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
+The solution set must not contain duplicate quadruplets.
+
+Tags Expand
+Two Pointers Sort Hash Table Array
+
+*/
+
+/*
+Thoughts:
+Can't do for loop over 3sum, which is O(n^3), not doable.
+We can break the nums into 2 major parts by index i.
+1st part: from [0 ~ i], we'll try all possible ways to pair [x, i] and store the sum of nums[x]+nums[i] in map.
+Note: key is sum, and the value is a hashSet of ArrayList. Where the hashset has itself functions to tell duplicate of pairs.
+2nd part: try [i + 1, end], see if any combination sum that makes: target - sum exist in map. -> becomes same old 2sum problem.
+O(n)
+*/
+/**
+ Why having below front-pair-building after previous for end-pair-checking for loop?
+ Here: we build [0 ~ i], and in next round, when we processs [i + 1, end], pairs built among [0~i] below will all be used.
+ Rather: if we have lift the for loop below to calculate [0~i] before the end-pair-checking of same [i~end],
+ there is one index at [i] will overlap, which turns to be incorrect.
+ Therefore, we build front-pairs aftwarwards: it's building [0~i] here, which aims to help next round of end-pair-checking on [i+1, end].
+*/
+class Solution {
+ public List> fourSum(int[] nums, int target) {
+ List> result = new ArrayList<>();
+ if (nums == null || nums.length <= 3) return result;
+
+ int n = nums.length;
+ Arrays.sort(nums);
+ Map> map = new HashMap<>();
+ Set cache = new HashSet<>();
+ for (int i = 0; i < n; i++) {
+ // Check if [i + 1, end] can be added up to target
+ for (int k = i + 1; k < n; k++) {
+ int sum = nums[i] + nums[k];
+ if (map.containsKey(target - sum)) {// Try to match up the 4 pairs
+ for (List frontPair : map.get(target - sum)) {
+ List list = Arrays.asList(frontPair.get(0), frontPair.get(1), nums[i], nums[k]);
+ String key = buildKey(list);
+ if (!cache.contains(key)) {
+ result.add(list);
+ cache.add(key);
+ }
+ }
+ }
+ }
+
+ // Build up the pair from [0 ~ i]
+ for (int j = 0; j < i; j++) {
+ int sum = nums[j] + nums[i];
+ map.putIfAbsent(sum, new HashSet<>());
+ map.get(sum).add(Arrays.asList(nums[j], nums[i]));
+ }
+ }
+ return result;
+ }
+
+ private String buildKey(List list) {
+ StringBuffer sb = new StringBuffer();
+ for (int num : list) sb.append(num + "@");
+ return sb.toString();
+ }
+}
+
+
+
+/*
+Thoughts
+Perform another layer outside of 3SUM. O(n^3).
+Note: If try to divide and perform two 2SUM, it will be a bit difficult. Refer to http://blog.csdn.net/linhuanmars/article/details/24826871
+
+*/
+public class Solution {
+
+ public ArrayList> fourSum(int[] numbers, int target) {
+ ArrayList> rst = new ArrayList>();
+ if(numbers == null || numbers.length < 4) {
+ return rst;
+ }
+ Arrays.sort(numbers);
+ //Pick 1st element
+ for (int i = 0; i < numbers.length - 3; i++) {
+ if (i != 0 && numbers[i] == numbers[i - 1]) {//Check for duplicate of 1st element
+ continue;
+ }
+ //Pick 2nd element
+ for (int j = i + 1; j < numbers.length - 2; j++) {
+ if (j != i + 1 && numbers[j] == numbers[j - 1]) {//Check for duplicate of 2nd element
+ continue;
+ }
+ //Pick 3rd and 4th element
+ int third = j + 1;
+ int fourth = numbers.length - 1;
+ while (third < fourth) {
+ int sum = numbers[i] + numbers[j] + numbers[third] + numbers[fourth];
+ if (sum < target) {
+ third++;
+ } else if (sum > target) {
+ fourth--;
+ } else {//sum == target
+ ArrayList list = new ArrayList();
+ list.add(numbers[i]);
+ list.add(numbers[j]);
+ list.add(numbers[third]);
+ list.add(numbers[fourth]);
+ rst.add(list);
+ third++;
+ fourth--;
+ while (third < fourth && numbers[third] == numbers[third - 1]) {
+ third++;
+ }
+ while (third < fourth && numbers[fourth] == numbers[fourth + 1]){
+ fourth--;
+ }
+ }
+ }
+ }
+ }
+ return rst;
+ }
+}
+
+
+/*
+NOT Complete yet. Has a order issue in HashSet
+http://lifexplorer.me/leetcode-3sum-4sum-and-k-sum/
+Thoughts:
+Utilize 2Sum.
+
+Notes 2017: no need to create a new class Pair. We can just use list in HashSet, which compairs the list element and eleminate duplicated list.
+*/
+
+public class Solution {
+ //Create class Pair for HashSet to use
+ class Pair {
+ Integer x;
+ Integer y;
+
+ public Pair(int x, int y){
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public int hashCode(){
+ return this.x.hashCode() + this.y.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object d) {
+ if (!(d instanceof Pair)) {
+ return false;
+ }
+ Pair p = (Pair)d;
+ return (this.x == p.x) && (this.y == p.y);
+ }
+ }
+
+ public ArrayList> fourSum(int[] numbers, int target) {
+ ArrayList> rst = new ArrayList>();
+ if (numbers == null || numbers.length < 4) {
+ return rst;
+ }
+ Arrays.sort(numbers);
+ HashMap> map = new HashMap>();
+ for (int i = 0; i < numbers.length; i++) {
+ for (int j = i + 1; j < numbers.length; j++) {
+ int sum = numbers[i] + numbers[j];
+ if (map.containsKey(target - sum)) {
+ for (Pair p : map.get(target - sum)) {
+ ArrayList list = new ArrayList();
+ list.add(p.x);
+ list.add(p.y);
+ list.add(numbers[i]);
+ list.add(numbers[j]);
+ if (!rst.contains(list)) {
+ rst.add(list);
+ }
+ }
+ }
+ }
+ //Add all pairs up to i
+ for (int j = 0; j < i; j++) {
+ int sum = numbers[i] + numbers[j];
+ if (!map.containsKey(sum)) {
+ map.put(sum, new HashSet());
+ }
+ map.get(sum).add(new Pair(numbers[j], numbers[i]));
+ }
+ }
+
+ return rst;
+ }
+
+}
+
+```
\ No newline at end of file
diff --git a/Java/A+B.java b/Java/A+B.java
deleted file mode 100644
index 61eaebc..0000000
--- a/Java/A+B.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-For given numbers a and b in function aplusb, return the sum of them.
-
-Note
-You don't need to parse the input and output. Just calculate and return.
-
-Example
-If a=1 and b=2 return 3
-
-Challenge
-Can you do it with out + operation?
-
-Clarification
-Are a and b both 32-bit integers?
-
- - Yes.
-
-Thinking process:
-Bit operation. Just to remmeber this problem, doing A+B using bit.
-*/
-
-class Solution {
- /*
- * param a: The first integer
- * param b: The second integer
- * return: The sum of a and b
- */
- public int aplusb(int a, int b) {
- while (b != 0) {
- int carry = a & b;
- a = a ^ b;
- b = carry << 1;
- }
- return a;
- }
-};
-
diff --git a/Java/Accounts Merge.java b/Java/Accounts Merge.java
new file mode 100644
index 0000000..160c27e
--- /dev/null
+++ b/Java/Accounts Merge.java
@@ -0,0 +1,185 @@
+M
+1532588768
+tags: DFS, Union Find, Hash Table, Hash Table
+
+给一串account in format `[[name, email1, email2, email3], [name2, email,..]]`.
+
+要求把所有account merge起来 (可能多个record记录了同一个人, by common email)
+
+
+#### Union Find
+- 构建 `Map`, 然后再反向整合: parent -> list of email
+- init with for all emails
+- 因为不同account可能串email, 那么把所有email union的时候, 不同account 的email也会被串起来
+- 最终: 所有的email都被union起来, 指向一个各自union的 parent email
+- UnionFind 的 parent map 可以反向输出所有 child under parent.
+- 同时要维护一个 account name> 的map, 最终用来输出.
+
+#### Hash Table solution, passed but very slow
+- Definitely need iterate over accounts: merge them by email.
+- Account object {name, list of email}
+- map
+- 1. iterate over accounts
+- 2. find if 'account' exist; if does, add emails
+- 3. if not, add account to list and to map. map all emails to accounts.
+- output -> all accounts, and sort emails
+- space O(mn): m row, n = emails
+- time O(mn)
+
+```
+/*
+Given a list accounts, each element accounts[i] is a list of strings,
+where the first element accounts[i][0] is a name,
+and the rest of the elements are emails representing emails of the account.
+
+Now, we would like to merge these accounts. Two accounts definitely belong to the same person
+if there is some email that is common to both accounts.
+Note that even if two accounts have the same name,
+they may belong to different people as people could have the same name.
+A person can have any number of accounts initially, but all of their accounts definitely have the same name.
+
+After merging the accounts, return the accounts in the following format:
+the first element of each account is the name, and the rest of the elements are emails in sorted order.
+The accounts themselves can be returned in any order.
+
+Example 1:
+Input:
+accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]]
+Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]]
+Explanation:
+The first and third John's are the same person as they have the common email "johnsmith@mail.com".
+The second John and Mary are different people as none of their email addresses are used by other accounts.
+We could return these lists in any order, for example the answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'],
+['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted.
+Note:
+
+The length of accounts will be in the range [1, 1000].
+The length of accounts[i] will be in the range [1, 10].
+The length of accounts[i][j] will be in the range [1, 30].
+
+*/
+
+// Hash Table
+class Solution {
+ class Account {
+ String name;
+ Set emails;
+ public Account(String name, Set emails) {
+ this.name = name;
+ this.emails = emails;
+ }
+ }
+
+ private boolean validate(List> accounts) {
+ return accounts == null || accounts.size() == 0 || accounts.get(0) == null || accounts.get(0).size() == 0;
+ }
+ public List> accountsMerge(List> accounts) {
+ List> rst = new ArrayList<>();
+ if (validate(accounts)) return rst;
+
+ // map, list, populate
+ Map map = new HashMap<>();
+ Set mergedAccounts = new HashSet<>();
+ for (List row : accounts) {
+ Account account = new Account(row.get(0), new HashSet<>());
+ Set existingAccounts = new HashSet<>();
+ for (int i = 1; i < row.size(); i++) {
+ account.emails.add(row.get(i));
+ if (map.containsKey(row.get(i))) {
+ Account existingAccount = map.get(row.get(i));
+ mergedAccounts.remove(existingAccount);
+ account.emails.addAll(existingAccount.emails);
+ }
+ }
+ mergedAccounts.add(account);
+ for (String email: account.emails) {
+ map.put(email, account);
+ }
+ }
+
+ // output as needed
+ for (Account account : mergedAccounts) {
+ List row = new ArrayList<>();
+ List emails = new ArrayList<>(account.emails);
+ Collections.sort(emails);
+ row.add(account.name);
+ row.addAll(emails);
+ rst.add(row);
+ }
+
+ return rst;
+ }
+}
+
+
+/*
+Union Find
+Approach similar to LintCode(Find the weak connected component in directed graph)
+UnionFind: Map
+1. Group account into union. ( don't forget to preserve email -> name mapping)
+2. Group parent -> children
+3. output
+*/
+class Solution {
+ Map accountMap = new HashMap<>();
+ Map parentMap = new HashMap<>();
+
+ public List> accountsMerge(List> accounts) {
+ List> rst = new ArrayList<>();
+ if (validate(accounts)) return rst;
+
+ buildUnionFind(accounts);
+
+ for (List account : accounts) {
+ for (int i = 1; i < account.size() - 1; i++) {
+ union(account.get(i), account.get(i + 1)); // email across acounts will be auto-merged/linked in unionFind
+ }
+ }
+
+ Map> result = new HashMap<>();
+ for (String email : parentMap.keySet()) {
+ String parent = find(email);
+ result.putIfAbsent(parent, new ArrayList<>());
+ result.get(parent).add(email);
+ }
+
+ for (List list: result.values()) {
+ Collections.sort(list);
+ list.add(0, accountMap.get(list.get(0)));
+ rst.add(list);
+ }
+
+ return rst;
+ }
+
+ private boolean validate(List> accounts) {
+ return accounts == null || accounts.size() == 0 || accounts.get(0) == null || accounts.get(0).size() == 0;
+ }
+
+ private void buildUnionFind(List> accounts) {
+ for (List account : accounts) {
+ String name = account.get(0);
+ for (int i = 1; i < account.size(); i++) {
+ accountMap.put(account.get(i), name); // email -> name mapping
+ parentMap.put(account.get(i), account.get(i)); // union parent map
+ }
+ }
+ }
+
+ private String find(String email) {
+ String parent = parentMap.get(email);
+ if (parent.equals(parentMap.get(parent))) {
+ return parent;
+ }
+ return find(parent);
+ }
+
+ private void union(String a, String b) {
+ String parentA = find(a);
+ String parentB = find(b);
+ if (!parentA.equals(parentB)) {
+ parentMap.put(parentA, parentB);
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Add Binary.java b/Java/Add Binary.java
old mode 100644
new mode 100755
index e8d1f35..8d600f8
--- a/Java/Add Binary.java
+++ b/Java/Add Binary.java
@@ -1,4 +1,21 @@
+E
+1533603550
+tags: Math, String, Two Pointers
+
+#### Two pointers
+- Use two pointers i, j to track the 2 strings
+- Add when i and j are applicable. While (i >= 0 || j >= 0)
+- StringBuffer.insert(0, x);
+- handle carry
+
+#### wrong: convert to int
+- 土办法没技术,把binary换成数字,加起来,再换成binary
+- 如果input很大,那么很可能int,long都hold不住。不保险。
+
+```
/*
+Add Binary
+
Given two binary strings, return their sum (also a binary string).
Example
@@ -9,10 +26,93 @@ Given two binary strings, return their sum (also a binary string).
Return 100
Tags Expand
-String Binary
+String Binary Facebook
+*/
+public class Solution {
+ public String addBinary(String a, String b) {
+ StringBuilder sb = new StringBuilder();
+ int i = a.length() - 1, j = b.length() -1, carry = 0;
+ while (i >= 0 || j >= 0) {
+ int sum = carry;
+ if (i >= 0) sum += a.charAt(i--) - '0';
+ if (j >= 0) sum += b.charAt(j--) - '0';
+ sb.insert(0, sum % 2);
+ carry = sum / 2;
+ }
+ if (carry != 0) sb.insert(0, carry);
+ return sb.toString();
+ }
+}
+
+/*
+Thoughts:
+Can't just convert to int because of Integer.MAX_VALUE limitation.
+Convert to char, and add up all chars
+*/
+class Solution {
+ public String addBinary(String a, String b) {
+ if (a == null || b == null) {
+ return a == null ? b : a;
+ }
+ int m = a.length();
+ int n = b.length();
+ int size = Math.max(m, n);
+ char[] result = new char[size];
+ char[] longArray = m > n ? a.toCharArray() : b.toCharArray();
+ char[] shortArray = m > n ? b.toCharArray() : a.toCharArray();
+ int diff = longArray.length - shortArray.length; // important
+ int carry = 0;
+ for (int i = size - 1; i >= 0; i--) {
+ int sum = carry + (longArray[i] - '0');
+ if (i - diff >= 0) {
+ sum += (shortArray[i - diff] - '0');
+ }
+ carry = sum / 2;
+ result[i] = (char)(sum % 2 + '0');
+ }
+
+ if (carry != 0) {
+ return "1" + new String(result);
+ }
+ return new String(result);
+ }
+}
+/*
+ Thought:
+ Use binary property, add all and move carry-on
+ String to charArray
+*/
+
+public class Solution {
+ public String addBinary(String a, String b) {
+ if (a == null || b == null || a.length() == 0 || b.length() == 0) {
+ return null;
+ }
+ char[] shortArr = a.length() < b.length() ? a.toCharArray() : b.toCharArray();
+ char[] longArr = a.length() < b.length() ? b.toCharArray() : a.toCharArray();
+ int carry = 0;
+ int shortVal = 0;
+ int nextCarry = 0;
+ int diff = longArr.length - shortArr.length;
+ for (int i = longArr.length - 1; i >= 0; i--) {
+ shortVal = (i - diff) >= 0 ? shortArr[i - diff] - '0': 0;
+ nextCarry = (longArr[i] - '0' + shortVal + carry) / 2;
+ longArr[i] =(char)((longArr[i] - '0' + shortVal + carry) % 2 + '0');
+ carry = nextCarry;
+ }
+
+ if (carry != 0) {
+ return "1" + new String(longArr);
+ }
+
+ return new String(longArr);
+ }
+}
+
+/*
//Thougths:
1. Turn string binary format into integer
2. add integer
@@ -20,7 +120,6 @@ Given two binary strings, return their sum (also a binary string).
Note: this just test if we know how to manipulate string/binary/Integer
*/
-
public class Solution {
/**
* @param a a number
@@ -39,3 +138,7 @@ public String addBinary(String a, String b) {
return Integer.toBinaryString(sum);
}
}
+
+
+
+```
diff --git a/Java/Add Digits.java b/Java/Add Digits.java
new file mode 100644
index 0000000..f38d6fd
--- /dev/null
+++ b/Java/Add Digits.java
@@ -0,0 +1,48 @@
+E
+1519709532
+tags: Math
+
+方法1: 普通做法就是按照题意, double-while loop把数字加起来. 第一层循环是O(n), 然后第二层循环就少很多数位, overall O(n)
+
+方法2: 找数学规律, 每过9个数字, 取mod就会开始重复, 所以给所有数字取mod 就可以间接找到答案. O(1)
+
+```
+/*
+Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.
+
+For example:
+
+Given num = 38, the process is like: 3 + 8 = 11, 1 + 1 = 2. Since 2 has only one digit, return it.
+
+Follow up:
+Could you do it without any loop/recursion in O(1) runtime?
+*/
+
+/*
+Thoughts:
+Keep adding until result < 10
+Double-while loop: start with a num, calculate result, then num = result.
+*/
+class Solution {
+ public int addDigits(int num) {
+ if (num < 10) {
+ return num;
+ }
+ while (num > 9) {
+ int temp = 0;
+ while (num != 0) {
+ temp += num % 10;
+ num = num / 10;
+ }
+ num = temp;
+ }
+ return num;
+ }
+}
+
+class Solution {
+ public int addDigits(int num) {
+ return (num - 1) % 9 + 1;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Add Two Numbers II.java b/Java/Add Two Numbers II.java
old mode 100644
new mode 100755
index 55d3fba..7d9a42e
--- a/Java/Add Two Numbers II.java
+++ b/Java/Add Two Numbers II.java
@@ -1,9 +1,15 @@
-方向相反。巧用stack.
+M
+1519711895
+tags: Linked List
+
+Singly-linked list需要reverse, 用stack.
+最终结果要恢复成input list 那样的sequence方向, 用stack一个个pop()刚好就可以做到.
+
+加法都一样:
+ 1. sum = carry
+ 2. carry = sum / 10
+ 3. sum = sum % 10;
-做加法都一样:
-1. carrier
-2. carrier = (rst + carrier) / 10
-3. rst = (rst + carrier) % 10
```
/*
You have two numbers represented by a linked list, where each node contains a single digit.
@@ -19,6 +25,67 @@
Linked List High Precision
*/
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ * int val;
+ * ListNode next;
+ * ListNode(int x) { val = x; }
+ * }
+ */
+/*
+Thoughts:
+Reverse the items in stack.
+Add two stacks and save the result in stack as well.
+Use top of the result stack as header of the result ListNode
+Time, Space: O(n)
+*/
+class Solution {
+ public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
+ if (l1 == null || l2 == null) {
+ return l1 == null ? l2 : l1;
+ }
+ Stack s1 = new Stack();
+ Stack s2 = new Stack();
+ Stack result = new Stack();
+ while (l1 != null) {
+ s1.push(l1);
+ l1 = l1.next;
+ }
+ while (l2 != null) {
+ s2.push(l2);
+ l2 = l2.next;
+ }
+
+ // sum up
+ int carry = 0;
+ while (!s1.isEmpty() || !s2.isEmpty()) {
+ int sum = carry;
+ if (!s1.isEmpty()) {
+ sum += s1.pop().val;
+ }
+ if (!s2.isEmpty()) {
+ sum += s2.pop().val;
+ }
+ carry = sum / 10;
+ sum = sum % 10;
+ result.push(new ListNode(sum));
+ }
+ if (carry != 0) {
+ result.push(new ListNode(carry));
+ }
+
+ // Convert to list
+ ListNode node = new ListNode(-1);
+ ListNode dummy = node;
+ while (!result.isEmpty()) {
+ node.next = result.pop();
+ node = node.next;
+ }
+ return dummy.next;
+ }
+}
+
/*
Thoughts: Different from Add Two Numbers I, which is in reverse order.
6 1 7
diff --git a/Java/Add Two Numbers.java b/Java/Add Two Numbers.java
new file mode 100755
index 0000000..6867a92
--- /dev/null
+++ b/Java/Add Two Numbers.java
@@ -0,0 +1,119 @@
+M
+1519711343
+tags: Linked List, Math
+
+LinkedList都已经反转好了,直接做.
+遍历两个l1,l2把carry-on处理好,每次生成一个新node,最后检查carry-on.
+
+跟Add Binary的理解方式一模一样.
+
+注意:
+Linked List 没有天然size.
+用DummyNode(-1).next来hold住结果.
+
+
+```
+/*
+You have two numbers represented by a linked list,
+where each node contains a single digit.
+The digits are stored in reverse order,
+such that the 1's digit is at the head of the list.
+Write a function that adds the two numbers and returns the sum as a linked list.
+
+Example
+Given 7->1->6 + 5->9->2. That is, 617 + 295.
+
+Return 2->1->9. That is 912.
+
+Given 3->1->5 and 5->9->2, return 8->0->8.
+
+Tags Expand
+Cracking The Coding Interview Linked List High Precision
+*/
+
+
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ * int val;
+ * ListNode next;
+ * ListNode(int x) {
+ * val = x;
+ * next = null;
+ * }
+ * }
+ */
+
+ /*
+Thoughts:
+The list has been reversed, just add them up.
+Append one more ListNode if there is an carry.
+*/
+class Solution {
+ public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
+ if (l1 == null || l2 == null) {
+ return l1 == null ? l2 : l1;
+ }
+ int carry = 0;
+ ListNode node = new ListNode(-1);
+ ListNode head = node;
+ // Add l1 and l2
+ while (l1 != null || l2 != null) {
+ int sum = carry;
+ if (l1 != null) {
+ sum += l1.val;
+ l1 = l1.next;
+ }
+ if (l2 != null) {
+ sum += l2.val;
+ l2 = l2.next;
+ }
+ carry = sum / 10;
+ sum = sum % 10;
+ node.next = new ListNode(sum);
+ node = node.next;
+ }
+
+ // Finish adding carry
+ if (carry != 0) {
+ node.next = new ListNode(carry);
+ }
+
+ return head.next;
+ }
+}
+
+// Previous solution
+public class Solution {
+ /**
+ * @param l1: the first list
+ * @param l2: the second list
+ * @return: the sum list of l1 and l2
+ */
+ public ListNode addLists(ListNode l1, ListNode l2) {
+ ListNode rst = new ListNode(0);
+ ListNode dummy = rst;
+ int carrier = 0;
+ //while
+ while (l1 != null || l2 != null) {
+ if (l1 != null) {
+ carrier += l1.val;
+ l1 = l1.next;
+ }
+ if (l2 != null) {
+ carrier += l2.val;
+ l2 = l2.next;
+ }
+ rst.next = new ListNode(carrier % 10);
+ carrier = carrier / 10;
+ rst = rst.next;
+ }
+ //check the carrier
+ if (carrier == 1) {
+ rst.next = new ListNode(1);
+ }
+ return dummy.next;
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/Add and Search Word - Data structure design.java b/Java/Add and Search Word - Data structure design.java
new file mode 100755
index 0000000..321f72d
--- /dev/null
+++ b/Java/Add and Search Word - Data structure design.java
@@ -0,0 +1,181 @@
+M
+1520491896
+tags: Backtracking, Design, Trie
+
+Trie结构, prefix tree的变形: '.'可以代替任何字符,那么就要iterate这个node所有的children.
+
+节点里面有char, isEnd, HashMap
+Build trie = Insert word:没node就加,有node就移动。
+Search word:没有node就报错. 到结尾return true
+
+这题因为'.'可以代替任何possible的字符,没一种都是一个新的path,所以recursive做比较好些。
+(iterative就要queue了,麻烦点)
+
+```
+/*
+Design a data structure that supports the following two operations: addWord(word) and search(word)
+
+search(word) can search a literal word or a regular expression string containing only letters a-z or ..
+
+A . means it can represent any one letter.
+
+Example
+addWord("bad")
+addWord("dad")
+addWord("mad")
+search("pad") // return false
+search("bad") // return true
+search(".ad") // return true
+search("b..") // return true
+Note
+You may assume that all words are consist of lowercase letters a-z.
+
+Tags Expand
+Trie
+*/
+
+/*
+Thougths:
+Use Trie to store the letters and mark end letter with end = true
+Trie structure:
+class TrieNode {
+ HashMap map;
+ boolean isEnd;
+}
+During search, when facing '.', try all possible characters with the given TrieNode.map
+*/
+class WordDictionary {
+ class TrieNode {
+ HashMap map;
+ boolean end;
+ TrieNode() {
+ this.map = new HashMap<>();
+ this.end = false;
+ }
+ public HashMap getMap() {
+ return map;
+ }
+ public boolean isEnd() {
+ return this.end;
+ }
+ }
+
+ TrieNode root;
+ /** Initialize your data structure here. */
+ public WordDictionary() {
+ root = new TrieNode();
+ }
+
+ /** Adds a word into the data structure. */
+ public void addWord(String word) {
+ char[] arr = word.toCharArray();
+ TrieNode node = root;
+ for (char c : arr) {
+ HashMap map = node.getMap();
+ if (!map.containsKey(c)) {
+ map.put(c, new TrieNode());
+ }
+ node = map.get(c);
+ }
+ node.end = true;
+ }
+
+ /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
+ public boolean search(String word) {
+ return searchHelper(root, word, 0);
+ }
+
+ public boolean searchHelper(TrieNode root, String word, int index) {
+ if (index == word.length()) {
+ return root.isEnd();
+ }
+ TrieNode node = root;
+ char c = word.charAt(index);
+ HashMap map = node.getMap();
+ if (map.containsKey(c)) {
+ return searchHelper(map.get(c), word, index + 1);
+ } else if (c == '.') {
+ for (Map.Entry entry : map.entrySet()) {
+ if (searchHelper(entry.getValue(), word, index + 1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+}
+
+/*
+Build the WordDictionary like a TrieTree.
+Note: the '.' indicates any letter, which means we'd have to traverse through all possible letters in current level.
+Only one of the returning search results needs to be true
+
+Note:
+TrieNode contains that char, boolean, and HashMap of children
+*/
+
+public class WordDictionary {
+ class TrieNode{
+ HashMap children;
+ boolean isEnd;
+
+ public TrieNode() {
+ this.children = new HashMap();
+ this.isEnd = false;
+ }
+ }
+
+ TrieNode root;
+ public WordDictionary(){
+ this.root = new TrieNode();
+ }
+
+ // Adds a word into the data structure.
+ public void addWord(String word) {
+ TrieNode node = root;
+ for (int i =0; i < word.length(); i++) {
+ char c = word.charAt(i);
+ if (!node.children.containsKey(c)) {
+ node.children.put(c, new TrieNode());
+ }
+ node = node.children.get(c);
+ }
+ node.isEnd = true;
+ }
+
+ // Returns if the word is in the data structure. A word could
+ // contain the dot character '.' to represent any one letter.
+ public boolean search(String word) {
+ return searchHelper(root, word, 0);
+ }
+
+ public boolean searchHelper(TrieNode root, String word, int index) {
+ if (index == word.length()) {
+ return root.isEnd;
+ }
+ TrieNode node = root;
+ char c = word.charAt(index);
+ //border conditon:
+ if (node.children.containsKey(c)) {
+ return searchHelper(node.children.get(c), word, index + 1);
+ } else if (c == '.'){
+ for (Map.Entry entry : node.children.entrySet()) {
+ if (searchHelper(entry.getValue(), word, index + 1)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return false;
+ }
+ }
+}
+
+// Your WordDictionary object will be instantiated and called as such:
+// WordDictionary wordDictionary = new WordDictionary();
+// wordDictionary.addWord("word");
+// wordDictionary.search("pattern");
+
+
+```
\ No newline at end of file
diff --git a/Java/Alien Dictionary.java b/Java/Alien Dictionary.java
new file mode 100755
index 0000000..08fe8d9
--- /dev/null
+++ b/Java/Alien Dictionary.java
@@ -0,0 +1,228 @@
+H
+1533444111
+tags: Graph, Topological Sort, DFS, BFS, Backtracking
+
+给一个 array of strings: 假如这个array是按照一个新的字母排序表(alien dictionary)排出来的, 需要找到这个字母排序.
+
+有可能有多重排序的方法, 给出一种就可以.
+
+#### Graph
+- 本质: 上下两行string, 相对应的相同的index上, 如果字母不同, 就说明排在第一行的字母在字母表里更领先
+- 把 string array 变成topological sort的 graph: `map>`
+- 也可以`List[26] edges` (Course Schedule problem)
+- Build edges: find char diff between two row, and store the order indication into graph
+- 注意: indegree 永远是反向的 (跟 node to neighbors 相反的方式建立)
+
+#### BFS
+- topological sort 本身很好写, 但是要在题目中先了解到字母排序的本质
+- 其实上面这个排序的本质很好想, 但是把它具体化成构建graph的代码, 会稍微有点难想到
+- 算indegree, 然后用 BFS 来找到那些 inDegree == 0的 node
+- 最先inDegree == 0的node, 就排在字母表前面.
+- 下面的解法, 用了Graph: map>, 而不是 List[26], 其实更加试用超过26个字母的dictionary.
+- 如果 `inDegree.size() != result.length()`, there is nodes that did not make it into result.
+- ex: cycle nodes from input, where inDegree of a one node would never reduce to 0, and will not be added to result
+- In this case, it will be treated as invalid input, and return ""
+
+#### DFS
+- 跟BFS建立 grpah 的过程一模一样
+- DFS的不同在于: 用visited map 来标记走过的地方
+- 走到leaf的时候, add to result: 但因为走到了底才add, 最终的顺序应该颠倒 (或者, sb.insert(0, x) 直接用颠倒的顺序add)
+
+```
+
+/*
+
+There is a new alien language which uses the latin alphabet.
+However, the order among letters are unknown to you.
+You receive a list of non-empty words from the dictionary,
+where words are sorted lexicographically by the rules of this new language.
+Derive the order of letters in this language.
+
+Example 1:
+Given the following words in dictionary,
+
+[
+ "wrt",
+ "wrf",
+ "er",
+ "ett",
+ "rftt"
+]
+The correct order is: "wertf".
+
+Example 2:
+Given the following words in dictionary,
+
+[
+ "z",
+ "x"
+]
+The correct order is: "zx".
+
+Example 3:
+Given the following words in dictionary,
+
+[
+ "z",
+ "x",
+ "z"
+]
+The order is invalid, so return "".
+
+Note:
+You may assume all letters are in lowercase.
+You may assume that if a is a prefix of b, then a must appear before b in the given dictionary.
+If the order is invalid, return an empty string.
+There may be multiple valid order of letters, return any one of them is fine.
+
+*/
+
+Check:
+https://leetcode.com/problems/alien-dictionary/discuss/70119/Java-AC-solution-using-BFS
+
+/*
+Thoughts:
+Topological sort with BFS. The tricky part is: how to construct the node-edge relationship?
+For the same index of two strings: if the word1[index] != word2[index],
+that means c1 is at the leading position than c2 in topological order.
+
+Use this feature to build the edges.
+
+1. Build graph
+2. Calculate indegree
+3. BFS
+*/
+class Solution {
+ public String alienOrder(String[] words) {
+ if (words == null || words.length == 0) return "";
+
+ // Build graph && indegree map
+ Map> graph = new HashMap<>();
+ Map inDegree = new HashMap<>();
+ build(graph, inDegree, words);
+
+ // Topological sort with BFS
+ return topoSort(graph, inDegree);
+ }
+
+ private void build(Map> graph, Map inDegree, String[] words) {
+ // Init graph, inDegree map
+ for (String word : words) {
+ for (char c : word.toCharArray()) {
+ graph.putIfAbsent(c, new ArrayList<>());
+ inDegree.putIfAbsent(c, 0);
+ }
+ }
+ // Build graph: find char diff between curr row and next row => build graph edge and increase inDegree relationship
+ // always compare same index on: words[i] -> words[i+1]
+ // if c1 != c2, build graph and inDegree map and break: later index does not have any more relationship.
+ for (int i = 0; i < words.length - 1; i++) {
+ int index = 0;
+ while (index < words[i].length() && index < words[i + 1].length()) {
+ char c1 = words[i].charAt(index);
+ char c2 = words[i + 1].charAt(index);
+ if (c1 != c2) {
+ graph.get(c1).add(c2);
+ inDegree.put(c2, inDegree.get(c2) + 1);
+ break;
+ }
+ index++;
+ }
+ }
+ }
+
+ private String topoSort(Map> graph, Map inDegree) {
+ Queue queue = new LinkedList<>();
+ for (char c : inDegree.keySet()) { // Build queue with item of inDegree==0: means no edge points towards it.
+ if (inDegree.get(c) == 0) queue.offer(c);
+ }
+
+ StringBuffer sb = new StringBuffer();
+ while (!queue.isEmpty()) {
+ char c = queue.poll();
+ sb.append(c);
+ for (char edgeNode : graph.get(c)) { // reduce edge degrees count since node:graph.get(c) has been processed
+ inDegree.put(edgeNode, inDegree.get(edgeNode) - 1);
+ if (inDegree.get(edgeNode) == 0) queue.offer(edgeNode);
+ }
+ }
+
+ if (sb.length() != graph.size()) return "";
+ return sb.toString();
+ }
+}
+
+
+/*
+Thoughts:
+DFS, mark visited. When dfs down to an leaf element,
+it'll be the last element of the final output. (reverse order)
+*/
+class Solution {
+ Map> graph = new HashMap<>();
+ Map visited = new HashMap<>();
+ StringBuffer sb = new StringBuffer();
+
+ public String alienOrder(String[] words) {
+ if (words == null || words.length == 0) {
+ return "";
+ }
+
+ // Build graph, and visited map.
+ buildGraph(words);
+
+ // Topological sort with dfs
+ for (char c : graph.keySet()) {
+ if (!dfs(c)) {
+ return "";
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private boolean dfs(Character c) {
+ if (visited.get(c) == 1) return true;
+ if (visited.get(c) == -1) return false;
+
+ visited.put(c, -1);
+ for (char edgeNode : graph.get(c)) {
+ if (!dfs(edgeNode)) {
+ return false;
+ }
+ }
+ visited.put(c, 1);
+ sb.insert(0, c); // leaf element, add to buffer
+ return true;
+ }
+
+ private void buildGraph (String[] words) {
+ // Create nodes
+ for (String word: words) {
+ for (char c : word.toCharArray()) {
+ if (!graph.containsKey(c)) {
+ graph.put(c, new ArrayList<>());
+ visited.put(c, 0);
+ }
+ }
+ }
+
+ // Build edges
+ for (int i = 0; i < words.length - 1; i++) {
+ int index = 0;
+ while (index < words[i].length() && index < words[i + 1].length()) {
+ char c1 = words[i].charAt(index);
+ char c2 = words[i + 1].charAt(index);
+ if (c1 != c2) {
+ graph.get(c1).add(c2);
+ break;
+ }
+ index++;
+ }
+ }
+ }
+}
+
+
+
+```
diff --git a/Java/Anagrams.java b/Java/Anagrams.java
old mode 100644
new mode 100755
index 2d1395c..b60c2cd
--- a/Java/Anagrams.java
+++ b/Java/Anagrams.java
@@ -1,24 +1,37 @@
-hashtable 的做法。
-toCharArray
-Arrays.sort
-Stirng.valueOf(char[])
+M
+1531455963
+tags: Array, Hash Table
+把anagram找到并output
+#### HashMap
+- 存在int[26], Arrays.toString(arr) 就是 string key: character frequency map
+- anagram都有一样的key, 存进hashmap
+- output anagrams
-http://www.jiuzhang.com/solutions/anagrams/
-做法不太一样 lOl
-1. take each string, count the occurrance of the 26 letters. save in int[]count.
-2. hash the int[] count and output a unique hash value.
- hash = hash * a + num
- a = a * b.
-3. save to hashmap in the same way as we do.
+#### HashMap + Sort
+- HashMap 的做法. sort每个string, 存进HashMap, 重复的就是anagrams,最后输出。
+- toCharArray
+- Arrays.sort
+- Stirng.valueOf(char[])
+- 时间n*L*O(logL),L是最长string的长度。
+
+#### Previous Notes
+- Arrays.toString(arr)的做法。arr是int[26], assuming only have 26 lowercase letters.
+- Count occurrance, 然后convert to String,作为map的key.
+- Time complexity: nO(L)
+- 另一种做法:http://www.jiuzhang.com/solutions/anagrams/
+- 1. take each string, count the occurrance of the 26 letters. save in int[]count.
+- 2. hash the int[] count and output a unique hash value; hash = hash * a + num; a = a * b.
+- 3. save to hashmap in the same way as we do.
+- 这一步把for s: strs 里面的时间复杂度降到了O(L). L = s.length().
+- Need to work on the getHash() function.
+- 时间变成n*O(L). Better.
-这一步把for s: strs
-里面的时间复杂度降到了O(L). L = s.length()
-而普通的,for 里面的时间复杂度是 Llog(L)
```
/*
+LintCode
Given an array of strings, return all groups of strings that are anagrams.
Example
@@ -34,6 +47,63 @@
*/
+public class Solution {
+ public List anagrams(String[] strs) {
+ List rst = new ArrayList<>();
+ if (strs == null || strs == null) return rst;
+ Map> map = new HashMap<>();
+ for (String word : strs){
+ int[] arr = new int[26];
+ for (char c : word.toCharArray()) arr[c - 'a']++;
+ String key = Arrays.toString(arr);
+ map.putIfAbsent(key, new ArrayList<>());
+ map.get(key).add(word);
+ }
+
+ for (List list : map.values()) {
+ if (list.size() >= 2) rst.addAll(list);
+ }
+ return rst;
+ }
+}
+
+/*
+//2.29.2016
+ use int[26] assuming it's all lowercase letters
+ count each string char in a letter array int[], convert the array into string.
+ HashMap carray string as key, and actualy string as value
+ outupt all values
+*/
+public class Solution {
+ public List anagrams(String[] strs) {
+ List rst = new ArrayList();
+ if (strs == null || strs.length == 0) {
+ return rst;
+ }
+ HashMap> map = new HashMap>();
+
+ for (int i = 0; i < strs.length; i++) {
+ int[] arr = new int[26];
+ for (int j = 0; j < strs[i].length(); j++) {
+ arr[strs[i].charAt(j) - 'a'] += 1;
+ }
+ String arrString = Arrays.toString(arr);
+ if (!map.containsKey(arrString)) {
+ map.put(arrString, new ArrayList());
+ }
+ map.get(arrString).add(strs[i]);
+ }
+
+ //Output
+ for (Map.Entry> entry : map.entrySet()) {
+ if (entry.getValue().size() >= 2)
+ rst.addAll(entry.getValue());
+ }
+
+ return rst;
+ }
+}
+
/*
diff --git a/Java/Array Partition I.java b/Java/Array Partition I.java
new file mode 100644
index 0000000..582ac3a
--- /dev/null
+++ b/Java/Array Partition I.java
@@ -0,0 +1,53 @@
+E
+1517467099
+tags: Array
+
+给串数字, size=2n, 找pairs, 然后需要sum of min(pair) 最大.
+
+(a1, b1), (a2, b2), ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible.
+
+#### Sort, basics
+- 从结果出发, 只需要找到加法的结果,而不强调具体配对.
+- 写一写example就能做
+- 找到排列取单数位的规律,再考虑负数和正数的相同规律,即可找到排列求解的方法。
+- sort, O(nlogn)
+
+
+```
+/*
+Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1, b1), (a2, b2), ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible.
+
+Example 1:
+Input: [1,4,3,2]
+
+Output: 4
+Explanation: n is 2, and the maximum sum of pairs is 4 = min(1, 2) + min(3, 4).
+Note:
+n is a positive integer, which is in the range of [1, 10000].
+All the integers in the array will be in the range of [-10000, 10000].
+*/
+
+/*
+Thoughts: goal is to find the half of the numbers' sum, and always pick the min value of the pair.
+Also, need to make the overall sum as large as possible: can't always choose the smallest numbers, but we can choose numbers at ascending order.
+1. sort array.
+2. only pick the even ones (starting from index 0)
+Note:
+1. use long to save result: never know what sum can occur in the process.
+2. sort the array
+O(nlogn)
+*/
+class Solution {
+ public int arrayPairSum(int[] nums) {
+ if (nums == null || nums.length <= 1) {
+ return 0;
+ }
+ Arrays.sort(nums);
+ long result = 0;
+ for (int i = 0; i < nums.length; i++) {
+ result += i % 2 == 0 ? nums[i] : 0;
+ }
+ return (int)result;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Backpack II.java b/Java/Backpack II.java
old mode 100644
new mode 100755
index c780c23..049d41c
--- a/Java/Backpack II.java
+++ b/Java/Backpack II.java
@@ -1,16 +1,32 @@
-做了backpack I, 这个就如出一辙。
-想法还是,选了A[i-1] 或者没选A[i].
-一路往前跑不回头。就出来了。
+M
+1524202756
+tags: DP, Backpack DP
+
+给i本书, 每本书有自己的重量 int[] A, 每本书有value int[] V
+
+背包有自己的大小M, 看最多能放多少value的书?
+
+#### Backpack DP
+- 做了Backpack I, 这个就如出一辙, 只不过: dp存的不是max weight, 而是 value的最大值.
+- 想法还是,选了A[i - 1] 或者没选A[i - 1]时候不同的value值.
+- 时间空间O(mn)
+- Rolling Array, 空间O(m)
+
+#### Previous DP Solution
+- 如果无法达到的w, 应该mark as impossible. 一种简单做法是mark as -1 in dp.
+- 如果有负数value, 就不能这样, 而是要开一个can[i][w]数组, 也就是backpack I 的原型.
+- 这样做似乎要多一些代码, 好像并不是非常需要
-O(m)的做法。想想,的确我们只care 最后一行,所以一个存value的就够了。 注意:和bakcpackI的 O(m)一样的,j是倒序的。如果没有更好的j,就不要更新。就是这个道理。
```
/*
-Given n items with size Ai and value Vi, and a backpack with size m. What's the maximum value can you put into the backpack?
+Given n items with size Ai and value Vi, and a backpack with size m.
+What's the maximum value can you put into the backpack?
Example
-Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4], and a backpack with size 10. The maximum value is 9.
+Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4], and a backpack with size 10.
+The maximum value is 9.
Note
You cannot divide item into small pieces and the total size of items you choose should smaller or equal to m.
@@ -22,8 +38,200 @@
LintCode Copyright Dynamic Programming Backpack
*/
+/**
+Thoughts:
+dp[i][j]: 前i item, 放进weight/size = j 的袋子里的最大value.
+constraint: weight
+result: aggregate item value
+ */
+public class Solution {
+ public int backPackII(int m, int[] A, int V[]) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1];
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) {
+ dp[i][j] = dp[i - 1][j];
+ if (j - A[i - 1] >= 0) {
+ dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + V[i - 1]);
+ }
+
+ }
+ }
+
+ return dp[n][m];
+ }
+}
+
+// Rolling array:
+public class Solution {
+ public int backPackII(int m, int[] A, int V[]) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[2][m + 1];
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) {
+ dp[i % 2][j] = dp[(i - 1) % 2][j];
+ if (j - A[i - 1] >= 0) {
+ dp[i % 2][j] = Math.max(dp[i % 2][j], dp[(i - 1) % 2][j - A[i - 1]] + V[i - 1]);
+ }
+
+ }
+ }
+
+ return dp[n % 2][m];
+ }
+}
/*
+Thoughts:
+Dealing with value, the dp[i][w] = max value that can be formed over i tems at weight w.
+Two conditions:
+1. didn't pick A[i - 1]: dp[i - 1][w], value sum does not change.
+2. Picked A[i - 1]: dp[i - 1][w - A[i - 1]] + V[i - 1];
+Find the max of the above two, and record.
+Initialize with dp[0][0] = -1: not possible to form w, so mark as -1, impossible.
+*/
+
+public class Solution {
+ public int backPackII(int m, int[] A, int V[]) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1]; // [5][5]
+
+ for (int j = 0; j <= m; j++) {
+ dp[0][j] = -1; // 0 items cannot form weight j, hence value -1, marking impossible
+ }
+ dp[0][0] = 0; // 0 items, 0 weight -> 0 value
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 1; j <= m; j++) {
+ dp[i][j] = dp[i - 1][j]; // 0
+ if (j - A[i - 1] >= 0 && dp[i - 1][j - A[i - 1]] != -1) {
+ dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + V[i - 1]);
+ }
+
+ }
+ }
+
+ int rst = 0;
+ for (int j = 0; j <= m; j++) {
+ if (dp[n][j] != -1) {
+ rst = Math.max(rst, dp[n][j]);
+ }
+ }
+ return rst;
+ }
+}
+
+// Rolling array
+public class Solution {
+ public int backPackII(int m, int[] A, int V[]) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[2][m + 1];
+ for (int j = 0; j <= m; j++) {
+ dp[0][j] = -1; // 0 items cannot form weight j, hence value -1, mark as impossible
+ }
+ dp[0][0] = 0; // 0 items, 0 weight -> 0 value
+ int curr = 0, prev;
+
+ for (int i = 1; i <= n; i++) {
+ // rolling index
+ prev = curr;
+ curr = 1 - prev;
+ for (int j = 1; j <= m; j++) {
+ dp[curr][j] = dp[prev][j]; // 0
+ if (j - A[i - 1] >= 0 && dp[prev][j - A[i - 1]] != -1) {
+ dp[curr][j] = Math.max(dp[curr][j], dp[prev][j - A[i - 1]] + V[i - 1]);
+ }
+ }
+ }
+
+ int rst = 0;
+ for (int j = 0; j <= m; j++) {
+ if (dp[curr][j] != -1) {
+ rst = Math.max(rst, dp[curr][j]);
+ }
+ }
+ return rst;
+ }
+}
+
+
+
+
+
+/*
+Initialize with dp[0][0] = 0.
+This will pass the test, however it's not 100% explicit
+*/
+public class Solution {
+ public int backPackII(int m, int[] A, int V[]) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1]; // [5][5]
+ dp[0][0] = 0; // 0 items, 0 weight -> 0 value
+ for (int j = 0; j <= m; j++) {
+ dp[0][j] = 0; // 0 items cannot form weight j, hence value 0
+ }
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 1; j <= m; j++) {
+ dp[i][j] = dp[i - 1][j]; // 0
+ if (j - A[i - 1] >= 0) {
+ dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + V[i - 1]);
+ }
+ }
+ }
+ return dp[n][m];
+ }
+}
+
+// Rolling array
+public class Solution {
+ public int backPackII(int m, int[] A, int V[]) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[2][m + 1]; // [5][5]
+ dp[0][0] = 0; // 0 items, 0 weight -> 0 value
+ for (int j = 0; j <= m; j++) {
+ dp[0][j] = 0; // 0 items cannot form weight j, hence value 0
+ }
+ int curr = 0, prev;
+
+ for (int i = 1; i <= n; i++) {
+ // rolling index
+ prev = curr;
+ curr = 1 - prev;
+ for (int j = 1; j <= m; j++) {
+ dp[curr][j] = dp[prev][j]; // 0
+ if (j - A[i - 1] >= 0) {
+ dp[curr][j] = Math.max(dp[curr][j], dp[prev][j - A[i - 1]] + V[i - 1]);
+ }
+ }
+ }
+ return dp[curr][m];
+ }
+}
+
+
+/*
+Previous Notes.
Thoughts:
In Backpack I, we store true/false to indicate the largest j in last dp row.
Here, we can store dp[i][j] == max value.
@@ -79,11 +287,12 @@ public int backPackII(int m, int[] A, int V[]) {
/*
To use just O(m) sapce.
- Just like in Backpack I, at the end, we only care about the last row. Why not just maintain a row, always keep the max value.
+ Just like in Backpack I, at the end, we only care about the last row.
+ Why not just maintain a row, always keep the max value.
Note: Only update dp[j] if adding A[i-1] would be greater than current dp[j]
- It's a bit hard to come up with this... but it's good exercise to build brain a bit.
+ It's a bit hard to come up with this... but it's good exercise.
*/
public class Solution {
@@ -110,6 +319,4 @@ public int backPackII(int m, int[] A, int V[]) {
-
-
```
\ No newline at end of file
diff --git a/Java/Backpack III.java b/Java/Backpack III.java
new file mode 100644
index 0000000..4b62fa6
--- /dev/null
+++ b/Java/Backpack III.java
@@ -0,0 +1,227 @@
+H
+1524723994
+tags: DP, Backpack DP
+
+给n种不同的物品, int[] A weight, int[] V value, 每种物品可以用无限次
+
+问最大多少value可以装进size是 m 的包?
+
+#### DP
+- 可以无限使用物品, 就失去了last i, last unique item的意义: 因为可以重复使用.
+- 所以可以转换一个角度:
+- 1. 用i **种** 物品, 拼出w, 并且满足题目条件(max value). 这里因为item i可以无限次使用, 所以考虑使用了多少次K.
+- 2. K虽然可以无限, 但是也被 k*A[i]所限制: 最大不能超过背包大小.
+- dp[i][w]: 前i种物品, fill weight w 的背包, 最大价值是多少.
+- dp[i][w] = max {dp[i - 1][w - k*A[i-1]] + kV[i-1]}, k >= 0
+- Time O(nmk)
+- 如果k = 0 或者 1, 其实就是 Backpack II: 拿或者不拿
+
+#### 优化
+- 优化时间复杂度, 画图发现:
+- 所计算的 (dp[i - 1][j - k*A[i - 1]] + k * V[i - 1])
+- 其实跟同一行的 dp[i][j-A[i-1]] 那个格子, 就多出了 V[i-1]
+- 所以没必要每次都 loop over k times
+- 简化: dp[i][j] 其中一个可能就是: dp[i][j - A[i - 1]] + V[i - 1]
+- Time O(mn)
+
+#### 空间优化到1维数组
+- 根据上一个优化的情况, 画出 2 rows 网格
+- 发现 dp[i][j] 取决于: 1. dp[i - 1][j], 2. dp[i][j - A[i - 1]]
+- 其中: dp[i - 1][j] 是上一轮 (i-1) 的结算结果, 一定是已经算好, ready to be used 的
+- 然而, 当我们 i++,j++ 之后, 在之前 row = i - 1, col < j的格子, 全部不需要.
+- 降维简化: 只需要留着 weigth 这个 dimension, 而i这个dimension 可以省略:
+- (i - 1) row 不过是需要用到之前算出的旧value: 每一轮, j = [0 ~ m], 那么dp[j]本身就有记录旧值的功能.
+- 变成1个一位数组
+- 降维优化的重点: 看双行的左右计算方向
+- Time(mn). Space(m)
+
+```
+/*
+Given n kind of items with size Ai and value Vi
+(each item has an infinite number available)
+and a backpack with size m.
+
+What's the maximum value can you put into the backpack?
+
+Notice
+You cannot divide item into small pieces and the total size of items
+you choose should smaller or equal to m.
+*/
+
+
+/*
+Thoughts:
+dp[i][w]: first i types of items to fill weight w, find the max value.
+1st loop: which type of item to pick from A
+2nd loop: weight from 0 ~ m
+3rd loop: # times when A[i] is used.
+
+Goal: dp[n][m]
+
+Condition1: didn't pick A[i - 1], dp[i][j] = dp[i - 1][j];
+Condition2: pickced A[i - 1], dp[i][j] = dp[i - 1][j - k * A[i - 1]] + k * V[i - 1];
+
+O(nmk)
+*/
+public class Solution {
+ public int backPackIII(int[] A, int[] V, int m) {
+ if (A == null || A.length == 0 || V == null || V.length == 0 || m <= 0) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1];
+ dp[0][0] = 0; // 0 items to fill 0 weight, value = 0
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 1; j <= m; j++) {
+ dp[i][j] = dp[i - 1][j];
+ for (int k = 1; k * A[i - 1] <= j; k++) {
+ dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * A[i - 1]] + k * V[i - 1]);
+ }
+ }
+ }
+
+ return dp[n][m];
+ }
+}
+
+/**
+Optimization1:
+- 优化时间复杂度, 画图发现:
+- 所计算的 (dp[i - 1][j - k*A[i - 1]] + k * V[i - 1])
+- 其实跟同一行的 dp[i][j-A[i-1]] 那个格子, 就多出了 V[i-1]
+- 所以没必要每次都 loop over k times
+- 简化: dp[i][j] 其中一个可能就是: dp[i][j - A[i - 1]] + V[i - 1]
+
+*/
+public class Solution {
+ public int backPackIII(int[] A, int[] V, int m) {
+ if (A == null || A.length == 0 || V == null || V.length == 0 || m <= 0) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1];
+ dp[0][0] = 0; // 0 items to fill 0 weight, value = 0
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) {
+ dp[i][j] = dp[i - 1][j];
+ if (j >= A[i - 1]) {
+ dp[i][j] = Math.max(dp[i][j], dp[i][j - A[i - 1]] + V[i - 1]);
+ }
+ }
+ }
+ return dp[n][m];
+ }
+}
+
+/**
+Optimization2:
+- 根据上一个优化的情况, 画出 2 rows 网格
+- 发现 dp[i][j] 取决于: 1. dp[i - 1][j], 2. dp[i][j - A[i - 1]]
+- 其中: dp[i - 1][j] 是上一轮 (i-1) 的结算结果, 一定是已经算好, ready to be used 的
+- 然而, 当我们 i++,j++ 之后, 在之前 row = i - 1, col < j的格子, 全部不需要.
+- 降维简化: 只需要留着 weigth 这个 dimension, 而i这个dimension 可以省略:
+- (i - 1) row 不过是需要用到之前算出的旧value: 每一轮, j = [0 ~ m], 那么dp[j]本身就有记录旧值的功能.
+*/
+public class Solution {
+ public int backPackIII(int[] A, int[] V, int m) {
+ if (A == null || A.length == 0 || V == null || V.length == 0 || m <= 0) {
+ return 0;
+ }
+ int n = A.length;
+ int[] dp = new int[m + 1]; // DP on weight
+ dp[0] = 0; // 0 items to fill 0 weight, value = 0
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = A[i - 1]; j <= m && j >= A[i - 1]; j++) {
+ dp[j] = Math.max(dp[j], dp[j - A[i - 1]] + V[i - 1]);
+ }
+ }
+ return dp[m];
+ }
+}
+
+/*
+Thoughts:
+Can pick any item for infinite times: there is no indicator of what's being picked last.
+We don't know which item && how many times it was picked.
+We should consider tracking: what type of items was picked how many times
+(consider once done with 1 type of item, move on to others and never re-pick)
+If A[i-1] was picked 0, 1, 2 ...., k times, then
+dp[i][w] = max{dp[i - 1][j - k*A[i - 1]] + k*V[i - 1]}, where k >= 0 -> infinite
+
+Space: O(mn)
+Time: O(m * m * n) = O(nm^2)
+*/
+public class Solution {
+ public int backPackIII(int[] A, int[] V, int m) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1]; // max value with i items of weight w.
+ for (int j = 0; j <= m; j++) {
+ dp[0][j] = -1; // 0 items cannot form j weight, hence value = 0
+ }
+ dp[0][0] = 0;
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) { // for all weight j at i items
+ for (int k = 0; k * A[i - 1] <= m; k++) { // use A[i-1] for k times
+ if (j - k * A[i - 1] >= 0 && dp[i - 1][j - k * A[i - 1]] != -1) {
+ dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * A[i - 1]] + k * V[i - 1]);
+ }
+ }
+ }
+ }
+ int rst = 0;
+ for (int j = 0; j <= m; j++) {
+ rst = Math.max(rst, dp[n][j]);
+ }
+ return rst;
+ }
+}
+
+
+
+// Optimization
+// curve up
+/*
+dp[i][w] = max{dp[i - 1][j - k*A[i - 1]] + k*V[i - 1]}, where k >= 0 -> infinite
+1. Every position, we are adding k*V[i - 1]
+2. If we draw out how V[i-1] was being added alone with k = [0 ~ ...], we realize:
+ the next i is basically: max{...all k's possibilities} + V[i - 1]
+So it reduces to:
+dp[i][w] = max{dp[i - 1][w], dp[i][w - A[i-1]] + V[i-1]}
+
+*/
+
+public class Solution {
+ public int backPackIII(int[] A, int[] V, int m) {
+ if (A == null || V == null || A.length != V.length) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1]; // max value with i items of weight w.
+ for (int j = 0; j <= m; j++) {
+ dp[0][j] = -1; // 0 items cannot form j weight, hence value = 0
+ }
+ dp[0][0] = 0;
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) { // for all weight j at i items
+ dp[i][j] = dp[i - 1][j];
+ if (j - A[i - 1] >= 0) {
+ dp[i][j] = Math.max(dp[i][j], dp[i][j - A[i - 1]] + V[i - 1]);
+ }
+ }
+ }
+ int rst = 0;
+ for (int j = 0; j <= m; j++) {
+ rst = Math.max(rst, dp[n][j]);
+ }
+ return rst;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Backpack V.java b/Java/Backpack V.java
new file mode 100644
index 0000000..45f5b99
--- /dev/null
+++ b/Java/Backpack V.java
@@ -0,0 +1,152 @@
+M
+1524205822
+tags: DP, Backpack DP
+
+#### Backpack DP
+- 与背包1不同: 这里不是check可能性(OR)或者最多能装的size是多少; 而是计算有多少种正好fill的可能性.
+- dp[i][w]: 用前i本书, 正好fill到 w weight的可能性.
+- 对于末尾, 还是两种情况:
+- 1. i-1位置没有加bag
+- 2. i-1位置加了bag
+- 两种情况可以fill满w的情况加起来, 就是我们要的结果.
+- 如常: dp[n + 1][w + 1]
+- 重点: dp[0][0] 表示0本书装满weight=0的包, 这里我们必须 dp[0][0] = 1, 给后面的 dp function 做base
+- Space, time: O(MN)
+- Rolling array, 空间优化, 滚动数组. Space: O(M)
+
+#### 降维打击, 终极优化
+- 分析row(i-1)的规律, 发现所有row(i)的值, 都跟row(i-1)的左边element相关, 而右边element是没用的.
+- 所以可以被override.
+- Space: O(M), 真*一维啊!
+- Time: O(MN)
+
+```
+/*
+Given n items with size nums[i] which an integer array and all positive numbers.
+An integer target denotes the size of a backpack.
+Find the number of possible ways of filling the backpack.
+
+Each item may only be used once
+*/
+
+
+/*
+Thoughts:
+We want to know with i items, how many ways can we add up to equal target?
+dp[i][w]: the # of ways to add up to w with i items.
+track back to i - 1:
+1. nums[i] was not picked : dp[i][w] = dp[i - 1][w]
+2. nums[i] was picked: dp[i][w] = dp[i - 1][w - nums[i]];
+
+initialization:
+dp[0][0~w] = 0;
+dp[0][0] = 1;
+
+Space: O(MN)
+Time: O(MN)
+*/
+public class Solution {
+ public int backPackV(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int n = nums.length;
+ int[][] dp = new int[n + 1][target + 1];
+ dp[0][0] = 1; // 0 items to form 0 weight
+ for (int j = 1; j <= target; j++) {
+ dp[0][j] = 0;
+ }
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= target; j++) {// (int j = target; j >= 0; j--) works as well, it doesn't matter
+ // Condition1:
+ dp[i][j] = dp[i - 1][j];
+ // Condition2:
+ if (j - nums[i - 1] >= 0) {
+ dp[i][j] += dp[i - 1][j - nums[i - 1]];
+ }
+ }
+ }
+ return dp[n][target];
+ }
+}
+
+
+// Improvement1: rolling array
+// Space O(M)
+public class Solution {
+ public int backPackV(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int n = nums.length;
+ int[][] dp = new int[2][target + 1];
+ dp[0][0] = 1; // 0 items to form 0 weight
+ for (int j = 1; j <= target; j++) {
+ dp[0][j] = 0;
+ }
+ int curr = 0, prev = 1;
+ for (int i = 1; i <= n; i++) {
+ prev = curr;
+ curr = 1 - curr;
+ for (int j = 0; j <= target; j++) {// (int j = target; j >= 0; j--) works as well, it doesn't matter
+ // Condition1:
+ dp[curr][j] = dp[prev][j];
+ // Condition2:
+ if (j - nums[i - 1] >= 0) {
+ dp[curr][j] += dp[prev][j - nums[i - 1]];
+ }
+ }
+ }
+ return dp[curr][target];
+ }
+}
+
+/*
+Improvement 降维
+Inner loop of weight needs to iterate from j = M -> 0
+We always use dp[i-1][w] or dp[i - 1][w - nums[i - 1]]:
+always using old values from last row right above at w index, or on the left side of the w index.
+
+All indexes on right side of w is not needed.
+
+Therefore, we can reduce the dp[][] into 1-D array.
+Note: j has to iterate from M -> 0, because we know on i - 1 row all indexes
+on right side of w on the right side can be overriden.
+
+if j = 0 -> M, it will override useful indexes.
+
+Space: O(n)
+Time: O(MN)
+*/
+
+public class Solution {
+ public int backPackV(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+ int n = nums.length;
+ int[] dp = new int [target + 1];
+ dp[0] = 1; // 0 items to form 0 weight
+ for (int j = 1; j <= target; j++) {
+ dp[j] = 0;
+ }
+
+ for (int i = 1; i <= n; i++) {
+ for (int j = target; j >= 0; j--) {// have to loop from M -> 0, for optimization
+ // Condition1: dp[j] = dp[j];
+ // Condition2:
+ if (j - nums[i - 1] >= 0) {
+ dp[j] += dp[j - nums[i - 1]];
+ }
+ }
+ // further simplify
+ //for (int j = target; j >= nums[i - 1]; j--) {
+ // dp[j] += dp[j - nums[i - 1]];
+ //}
+ }
+ return dp[target];
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/Backpack VI.java b/Java/Backpack VI.java
new file mode 100644
index 0000000..237a233
--- /dev/null
+++ b/Java/Backpack VI.java
@@ -0,0 +1,64 @@
+M
+1518420788
+tags: DP, Backpack DP
+
+给一个数组nums, 全正数, 无重复数字; 找: # of 拼出m的方法.
+
+nums 里的数字, 可以重复使用. 不同的order可以算作不同的拼法.
+
+#### Backpack DP
+- dp[i] 表示: # of ways to fill weight i
+- 1维: dp[w]: fill weigth w 有多少种方法. 前面有多少种可能性, 就sum多少个:
+- dp[w] = sum{dp[w - nums[i]]}, i = 0~n
+
+##### 分析
+- 拼背包时, 可以有重复item, 所以考虑'最后被放入的哪个unique item' 就没有意义了.
+- 背包问题, 永远和weight分不开关系.
+- 这里很像coin chagne: 考虑最后被放入的东西的value/weigth, 而不考虑是哪个.
+
+
+
+
+```
+/*
+Given an integer array nums with all positive numbers and no duplicates,
+find the number of possible combinations that add up to a positive integer target.
+
+Notice
+A number in the array can be used multiple times in the combination.
+Different orders are counted as different combinations.
+*/
+
+/*
+Thoughts:
+All backpack problems should have a status of weight. However, now the items can be reused, so there is no
+unique last item. We can't do [w - nums[i]].
+Instead of banking on last unique item, we should consider what's the last weight being added?
+Very similar to Coin Change.
+
+dp[w] = how many combinations to form weight w?
+Cound all ways:
+dp[w] = dp[w - nums[0]] + dp[w - nums[1]] + dp[w - nums[2]] + .... dp[w - nums[ n - 1]]
+*/
+public class Solution {
+ public int backPackVI(int[] nums, int target) {
+ if (nums == null || nums.length == 0) {
+ return 0;
+ }
+
+ int n = nums.length;
+ int[] dp = new int[target + 1];
+ dp[0] = 1; // fill 0 weight, always possible.
+
+ for (int i = 1; i <= target; i++) { // calc for all weights
+ for (int j = 0; j < n; j++) { // iterate over all nums
+ if (i - nums[j] >= 0) {
+ dp[i] += dp[i - nums[j]];
+ }
+ }
+ }
+
+ return dp[target];
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Backpack.java b/Java/Backpack.java
old mode 100644
new mode 100755
index 713728e..fac5121
--- a/Java/Backpack.java
+++ b/Java/Backpack.java
@@ -1,29 +1,50 @@
-记得这个DP。
-row是item大小: 0, A[0], A[1] ... A[A.length -1]
-col是背包累积的size: 0, 1, 2, ... m.
+M
+1524200994
+tags: DP, Backpack DP
+
+给i本书, 每本书有自己的重量 int[] A, 背包有自己的大小M, 看最多能放多少重量的书?
+
+#### Backpack DP 1
+- 简单直白的思考 dp[i][m]: 前i本书, 背包大小为M的时候, 最多能装多种的书?
+- **注意**: 背包问题, 重量weight一定要是一维.
+- dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + A[i - 1]);
+- 每一步都track 最大值
+- 最后return dp[n][m]
+- 时间空间 O(mn)
+- Rolling array, 空间O(m)
+
+#### Backpack DP 2
+- true/false求解, 稍微曲线救国: 重点是, 最后, 按照weight从大到小遍历, 第一个遇到true的, index就是最大值.
+- 考虑: 用i个item (可跳过地取), 是否能装到weight w?
+- 需要从'可能性'的角度考虑, 不要搞成单一的最大值问题.
+- 1. 背包可装的物品大小和总承重有关.
+- 2. 不要去找dp[i]前i个物品的最大总重, 找的不是这个.
+ dp[i]及时找到可放的最大sum, 但是i+1可能有更好的值, 把dp[i+1]变得更大更合适.
+
+##### 做法
+- boolean[][] dp[i][j]表示: 有前i个item, 用他们可否组成size为j的背包? true/false.
+- (反过来考虑了,不是想是否超过size j, 而是考虑是否能拼出exact size == j)
+- **注意**: 虽然dp里面一直存在i的位置, 实际上考虑的是在i位置的时候, 看前i-1个item.
+
+##### 多项式规律
+- 1. picked A[i-1]: 就是A[i-1]被用过, weight j 应该减去A[i-1]. 那么dp[i][j]就取决于dp[i-1][j-A[i-1]]的结果.
+- 2. did not pick A[i-1]: 那就是说, 没用过A[i-1], 那么dp[i][j]就取决于上一行d[i-1][j]
+- dp[i][j] = dp[i - 1][j] || dp[i - 1][j - A[i - 1]]
+
+##### 结尾
+- 跑一遍dp 最下面一个row. 从末尾开始找, 最末尾的一个j (能让dp[i][j] == true)的, 就是最多能装的大小 :)
+- 时间,空间都是:O(mn)
-想法是这样:
-dp[i][j]有这么i-1个item, 用他们可否组成size为j的背包?true/false. (反过来考虑了,不是想是否超过size j, 而是考虑是否能拼出exact size == j)。
-注意注意:虽然dp里面一直存在i的位置,实际上考虑的是在i位置的时候,看前i-1个item.
-看一遍code,会发现:
- 1. picked A[i-1] 如果上一个item, A[i-1]被加了上来, 用j-A[i-1]看看,是否这再前一步也true. true就好啦!
- 2. did not pick A[i-1]. 那就是说,不加上A[i-1], 上一行d[i-1][j]还是需要是true。
-最后:
-跑一边dp 最下面一个row. 从末尾开始找,最末尾的一个j (能让dp[i][j] == true)的,就是最多能装的大小 :)
-
-
-
-
-再有:
-O(m)的做法,注意j是倒序的啊!
```
/*
-Given n items with size Ai, an integer m denotes the size of a backpack.
+Given n items with size A[i], an integer m denotes the size of a backpack.
How full you can fill this backpack?
Example
-If we have 4 items with size [2, 3, 5, 7], the backpack size is 11, we can select [2, 3, 5], so that the max size we can fill this backpack is 10. If the backpack size is 12. we can select [2, 3, 7] so that we can fulfill the backpack.
+If we have 4 items with size [2, 3, 5, 7], the backpack size is 11, we can select [2, 3, 5],
+so that the max size we can fill this backpack is 10.
+If the backpack size is 12. we can select [2, 3, 7] so that we can fulfill the backpack.
You function should return the max size we can fill in the given backpack.
@@ -41,12 +62,176 @@
*/
+/*
+Thoughts:
+Backpack problem, always consider a dimension with weight/size.
+int dp[i][j]: with i items and backpack size/weight-limit of j, what's max weight can we put in?
+
+dp[i][j] depends on last item's size && what's the state with [i-1] items.
+
+dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + A[i - 1]);
+
+dp[0][0] = 0; no book, 0 weight limit
+dp[0][j] = 0; no book, can't fill bag
+dp[i][0] = 0; i books, but weight-limit = 0, can't fill
+*/
+public class Solution {
+ public int backPack(int m, int[] A) {
+ if (A == null || A.length < 0) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[n + 1][m + 1];
+
+ // Calculcate possibility for i items to fill up w weight
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) {
+ // default: item(i-1) not used:
+ dp[i][j] = dp[i - 1][j];
+ if (j - A[i - 1] >= 0) { // possible to use item(i-1)
+ dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + A[i - 1]); // use item(i-1)
+ }
+ }
+ }
+
+ return dp[n][m];
+ }
+}
+
+// Rolling array
+public class Solution {
+ public int backPack(int m, int[] A) {
+ if (A == null || A.length < 0) {
+ return 0;
+ }
+ int n = A.length;
+ int[][] dp = new int[2][m + 1];
+
+ // Calculcate possibility for i items to fill up w weight
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) {
+ // default: item(i-1) not used:
+ dp[i % 2][j] = dp[(i - 1) % 2][j];
+ if (j - A[i - 1] >= 0) { // possible to use item(i-1)
+ dp[i % 2][j] = Math.max(dp[i % 2][j], dp[(i - 1) % 2][j - A[i - 1]] + A[i - 1]); // use item(i-1)
+ }
+ }
+ }
+ return dp[n % 2][m];
+ }
+}
+
+/*
+Thoughts:
+DO NOT try to find the maxSum using given values: this approach f[i] only returns max sum,
+but does not guarantee to pick the most sutible items that maximize f[n].
+
+1. Always consider weight
+2. Consider it as a possibility problem based on weight 0 ~ m
+
+Using given items, can we fill backpack with size 0, size 1, size 2... size m - 1, and size m?
+We save these values with boolean dp[i][w]: using i items to fill size w, where i is the A index.
+
+Two conditions for calculating dp[i][w]
+1. i - 1 items filled up w, so dp[i][w] = dp[i - 1][w]. No need to add A[i - 1].
+2. i - 1 items fileld up w - A[i - 1]; once adding A[i - 1], it'll fill up w. dp[i][w] = dp[i - 1][w - A[i - 1]], so we are counting on if i - 1 items filled up weight: w - A[i - 1].
+
+We'll loop over j = 1 ~ m, and attempt to fill all sizes with i items.
+
+init:
+dp[0][0]: using 0 items to fill 0 space, sure. True.
+dp[0][1~m]: using 0 items to fill 1~m space, not gonna work. False.
+
+
+*/
+public class Solution {
+
+ public int backPack(int m, int[] A) {
+ if (A == null || A.length < 0) {
+ return 0;
+ }
+ int n = A.length;
+ boolean[][] dp = new boolean[n + 1][m + 1];
+
+ // weight 0 is a valid value.
+ // items does not have 0's item, so we need to init dp based for all entries where i == 0
+ dp[0][0] = true;
+ for (int j = 1; j <= m; j++) {
+ dp[0][j] = false;
+ }
+
+ // Calculcate possibility for i items to fill up w weight
+ for (int i = 1; i <= n; i++) {
+ for (int j = 0; j <= m; j++) {
+ // default: item(i-1) not used:
+ dp[i][j] = dp[i - 1][j];
+ if (j - A[i - 1] >= 0) { // possible to use item(i-1)
+ dp[i][j] |= dp[i - 1][j - A[i - 1]]; // use item(i-1)
+ }
+ }
+ }
+
+ // Find max weight size that makes dp[i][j] true
+ for (int j = m; j >= 0; j--) {
+ if (dp[n][j]) {
+ return j;
+ }
+ }
+ return 0;
+ }
+}
+
+/*
+Thoughts: rolling array.
+Always use i, and i - 1 dp. can replace the two index with
+curr, pre
+*/
+public class Solution {
+
+ public int backPack(int m, int[] A) {
+ if (A == null || A.length < 0) {
+ return 0;
+ }
+ int n = A.length;
+ boolean[][] dp = new boolean[2][m + 1];
+ int curr = 0;
+ int pre = 1;
+ // weight 0 is a valid value.
+ // items does not have 0's item, so we need to init dp based for all entries where i == 0
+ dp[curr][0] = true;
+ for (int j = 1; j <= m; j++) {
+ dp[curr][j] = false;
+ }
+
+ // Calculcate possibility for i items to fill up w weight
+ for (int i = 1; i <= n; i++) {
+ curr = pre;
+ pre = 1 - curr;
+ for (int j = 0; j <= m; j++) {
+ // default: item(i-1) not used:
+ dp[curr][j] = dp[pre][j];
+ if (j - A[i - 1] >= 0) { // possible to use item(i-1)
+ dp[curr][j] |= dp[pre][j - A[i - 1]]; // use item(i-1)
+ }
+ }
+ }
+
+ // Find max weight size that makes dp[i][j] true
+ for (int j = m; j >= 0; j--) {
+ if (dp[curr][j]) {
+ return j;
+ }
+ }
+ return 0;
+ }
+}
+
/*
Thoughts: Recap on 12.02.2015
State
DP[i][j]: i is the index of Ai, and j is the size from (0 ~ m).
- It means: depending if we added A[i-1], can we add up to j-space?Return ture/false.
- Note: that is, even j == 0, and I have a item with size == 2, I can still choose not to add, which means the backpack can reach j ==0. True.
+ It means: depending if we added A[i-1], can we full-fill j-space? Return ture/false.
+ Note: that is, even j == 0, and I have a item with size == 0. There is nothing to add, which means the backpack can reach j == 0. True.
However, if we have a item with size == 2, but I need to fill space == 1.
I will either pick/not pick item of size 2; either way, can't fill a backpack with size 1. False;
Function:
@@ -68,16 +253,16 @@ public int backPack(int m, int[] A) {
for (int i = 1; i <= A.length; i++) {
for (int j = 0; j <= m; j++) {
- //added A[i - 1]
+ //j is large enough:
if (j - A[i - 1] >= 0) {
+ //not added A[i - 1] or added A[i - 1]
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - A[i - 1]];
- } else {
- //not added A[i - 1];
+ } else {// j not large enough, ofcourse not adding A[i-1]
dp[i][j] = dp[i - 1][j];
}
}
}
-
+ //Largest possible size with dp[j] == true
for (int j = m; j >= 0; j--) {
if (dp[A.length][j]) {
return j;
@@ -89,53 +274,6 @@ public int backPack(int m, int[] A) {
-/*
-Thoughts:
-Well, I kind of forgot about how we did this in algorithm class, but here we go, after a bit research:
-DP[i][j] means: if i number of items in A, can we fill the bag size of j? Then, save a boolean in DP[i][j]. That means, if i items are too much for j?
-
-So, there are two cases:
-1. A[i] is unfortunately too big to fit into size j, so skip item A[i] and use DP[i-1][j].
-2. OR, the other case: A[i] fits in well. We realize 2 things:
- a. first (i-1)th items much fit in well into the bag size of (j - A[i - 1]): DP[i-1][j - A[i-1]]. Basically says items must be fit in (true) before adding A[i]
- b. AND (j - A[i - 1]) must >= 0 to have space for next item i.
-
-End:
-Iterate through j:(m ~ 0), and return j, if DP[A.length][j] is true. We are starting from m, because we need the largest number j.
-
-This is 2D array version: memory mxn, space mxn
-
-*/
-
-public class Solution {
- /**
- * @param m: An integer m denotes the size of a backpack
- * @param A: Given n items with size A[i]
- * @return: The maximum size
- */
- public int backPack(int m, int[] A) {
- if (A == null || m == 0) {
- return 0;
- }
-
- boolean[][] DP = new boolean[A.length + 1][m + 1];
- DP[0][0] = true;
- for (int i = 1; i <= A.length; i++) {
- for (int j = 0; j <= m; j++) {
- DP[i][j] = DP[i - 1][j] || (j - A[i - 1] >= 0 && DP[i - 1][j - A[i - 1]]);
- }
- }
-
- for (int j = m; j >= 0; j--) {
- if (DP[A.length][j]) {
- return j;
- }
- }
- return 0;
- }
-}
-
-
/*
1D array: memory mxn, space m. Tricky tho ...
diff --git a/Java/Backspace String Compare.java b/Java/Backspace String Compare.java
new file mode 100644
index 0000000..48428ed
--- /dev/null
+++ b/Java/Backspace String Compare.java
@@ -0,0 +1,69 @@
+E
+1533516441
+tags: Two Pointers, Stack
+
+```
+/*
+Given two strings S and T, return if they are equal when both are typed into empty text editors.
+# means a backspace character.
+
+Example 1:
+
+Input: S = "ab#c", T = "ad#c"
+Output: true
+Explanation: Both S and T become "ac".
+Example 2:
+
+Input: S = "ab##", T = "c#d#"
+Output: true
+Explanation: Both S and T become "".
+Example 3:
+
+Input: S = "a##c", T = "#a#c"
+Output: true
+Explanation: Both S and T become "c".
+Example 4:
+
+Input: S = "a#c", T = "b"
+Output: false
+Explanation: S becomes "c" while T becomes "b".
+Note:
+
+1 <= S.length <= 200
+1 <= T.length <= 200
+S and T only contain lowercase letters and '#' characters.
+Follow up:
+
+Can you solve it in O(N) time and O(1) space?
+
+*/
+
+/*
+Stack to take elements, and pop when # if reached.
+compare the two stacks at the end.
+time/space: O(n)
+*/
+class Solution {
+ public boolean backspaceCompare(String S, String T) {
+ if (S == null || T == null) return false;
+
+ return type(S).equals(type(T));
+ }
+
+ private String type(String s) {
+ Stack stack = new Stack<>();
+ for (char c : s.toCharArray()) {
+ if (c == '#') {
+ if (!stack.isEmpty()) stack.pop();
+ } else {
+ stack.push(c);
+ }
+ }
+ StringBuffer sb = new StringBuffer();
+ while (!stack.isEmpty()) {
+ sb.append(stack.pop());
+ }
+ return sb.toString();
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Balanced Binary Tree.java b/Java/Balanced Binary Tree.java
old mode 100644
new mode 100755
index 076d297..d036d7b
--- a/Java/Balanced Binary Tree.java
+++ b/Java/Balanced Binary Tree.java
@@ -1,17 +1,25 @@
-1. DFS using depth marker: 每个depth都存一下。然后如果有不符合条件的,存为-1.
- 一旦有-1, 就全部返回。
- 最后比较返回结果是不是-1. 是-1,那就false
+M
+1519713672
+tags: Tree, DFS
-2. 从基本的题目理解考虑,想到leaf node的情况。如果判断了leaf node, 那其他node应该就是可以recursive。
- 直接在isBalanced上面recursive.
- 然后这个可能是个小小的优化,因为不需要计算所有的depth.一旦发现一个false,其他的就不需要计算,直接返回了。
+给一个binary tree, 看是否是height-balanced
+
+#### DFS
+- DFS using depth marker: 每个depth都存一下。然后如果有不符合条件的,存为-1.
+- 一旦有 <0 或者差值大于1, 就全部返回Integer.MIN_VALUE. Integer.MIN_VALUE比较极端, 确保结果的正确性。
+- 最后比较返回结果是不是<0. 是<0,那就false.
+- Traverse 整个tree, O(n)
+
+
+#### DFS, maxDepth function
+- Same concept as in 1, but cost more traversal efforts.
```
/*
-46% Accepted
Given a binary tree, determine if it is height-balanced.
-For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
+For this problem, a height-balanced binary tree is defined as a binary tree,
+in which the depth of the two subtrees of every node never differ by more than 1.
Example
Given binary tree A={3,9,20,#,#,15,7}, B={3,#,20,15,7}
@@ -24,66 +32,47 @@
The binary tree A is a height-balanced binary tree, but B is not.
Tags Expand
-Tree Depth First Search
+Binary Search Divide and Conquer Recursion
*/
/**
- * Definition of TreeNode:
+ * Definition for a binary tree node.
* public class TreeNode {
- * public int val;
- * public TreeNode left, right;
- * public TreeNode(int val) {
- * this.val = val;
- * this.left = this.right = null;
- * }
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
* }
*/
-
/*
- 12.11.2015
- Recap:
- The original way of marking depth and -1 is good. However, that has to traverse entire tree.
-
- Today, let's think about the leaf case, and see if we can directly recurse on isBalanced itself.
- leaf case:
- root == null, return true;
- left = root.left; right = root.right;
- left == null && right == null : true;
-
- left == null && right != null && (right.left != null || right.right != null) {
- false;
- }
-
- need to isBalance(left) && isBalance(right).
+DFS: find each subtree's depth, and compare the two.
+However, making DFS for every node is very costly: the recursive calculations of depth are done repeatedly, so we want to at least tell, if a path has failed, no need to dive deep -> need a boolean-ish signature.
+However, we can't return both boolean && depth (we actually don't need other depth valuese greater than 1).
+Combine the boolean && depth signature to mark the failed case: by using a negative number.
*/
-
-public class Solution {
- /**
- * @param root: The root of binary tree.
- * @return: True if this Binary tree is Balanced, or false.
- */
+class Solution {
public boolean isBalanced(TreeNode root) {
- if (root == null || (root.left == null && root.right == null)) {
+ if (root == null) {
return true;
}
-
- TreeNode left = root.left;
- TreeNode right = root.right;
- //One of left or right is null.
- if (left == null && (right.left != null || right.right != null)) {
- return false;
- }
- if (right == null && (left.left != null || left.right != null)) {
- return false;
+ return markDepth(root) > 0;
+ }
+
+ private int markDepth(TreeNode node) {
+ if (node == null) {
+ return 0;
}
- //none of left or right is null
- return isBalanced(left) && isBalanced(right);
+ int leftDepth = markDepth(node.left);
+ int rightDepth = markDepth(node.right);
+ if (leftDepth < 0 || rightDepth < 0 || (Math.abs(leftDepth - rightDepth)) > 1) {
+ return Integer.MIN_VALUE;
+ }
+ return Math.max(leftDepth, rightDepth) + 1;
}
}
-
/*
Thinking process:
@@ -94,31 +83,90 @@ same process as maxDepth() method.
at the top return, check if -1.
*/
-public class Solution {
- /**
- * @param root: The root of binary tree.
- * @return: True if this Binary tree is Balanced, or false.
- */
+/* 3.3.2016 recap:
+ Recursive 1:
+ Use helper to calculate depth, and also check if left/right depth differ by 1. If all good, return actual depth
+*/
+
+ public class Solution {
public boolean isBalanced(TreeNode root) {
- return maxDepth(root) != -1;
+ if (root == null) {
+ return true;
+ }
+ return helper(root) > 0;
}
- public int maxDepth(TreeNode root) {
- if (root == null) {
+ public int helper(TreeNode node) {
+ if (node == null) {
return 0;
}
+ int leftDepth = helper(node.left);
+ int rightDepth = helper(node.right);
- int left = maxDepth(root.left);
- int right = maxDepth(root.right);
+ if (leftDepth < 0 || rightDepth < 0 || Math.abs(leftDepth - rightDepth) > 1) {
+ return Integer.MIN_VALUE;
+ }
- if (Math.abs(left - right) > 1 || left == -1 || right == -1) {
- return -1;
+ return Math.max(leftDepth, rightDepth) + 1;
+ }
+}
+
+
+/*
+ Recursive 2:
+ Calculate a node's maxDepth. Compare a parent node's sub tree for maxDepth
+*/
+public class Solution {
+ public boolean isBalanced(TreeNode root) {
+ if (root == null) {
+ return true;
}
+ int leftDepth = maxDepth(root.left);
+ int rightDepth = maxDepth(root.right);
- return Math.max(left, right) + 1;
+ if (Math.abs(leftDepth - rightDepth) > 1) {
+ return false;
+ }
+ return isBalanced(root.left) && isBalanced(root.right);
+ }
+
+ public int maxDepth(TreeNode node) {
+ if (node == null) {
+ return 0;
+ }
+ return Math.max(maxDepth(node.left), maxDepth(node.right)) + 1;
}
}
+
+/*
+ Failed Solution:
+ check cases:
+ root == null, return true;
+ left = root.left; right = root.right;
+ left == null && right == null : true;
+ left == null && right != null && (right.left != null || right.right != null) {
+ false;
+ }
+ return isBalance(left) && isBalance(right).
+
+ failed case:[1,2,2,3,3,null,null,4,4]
+ 1
+ 2 2
+ 3 3
+ 4 4
+Previous notes:
+2. 从基本的题目理解考虑,想到leaf node的情况。如果判断了leaf node, 那其他node应该就是可以recursive。
+ 直接在isBalanced上面recursive.
+ 关键return false的判断情况:如果有个node是null, 那么同一行相邻的那个,一旦有了children,那么就说明两个分支的depth已经是>=2了,那么就return false.
+
+ 然后这个可能是个小小的优化,因为不需要计算所有的depth.一旦发现一个false,其他的就不需要计算,直接返回了。
+
+
+
+*/
+
+
```
\ No newline at end of file
diff --git a/Java/Basic Calculator.java b/Java/Basic Calculator.java
new file mode 100644
index 0000000..b0151b8
--- /dev/null
+++ b/Java/Basic Calculator.java
@@ -0,0 +1,154 @@
+H
+1526882596
+tags: Stack, Math, Expression Tree, Binary Tree, Minimum Binary Tree
+
+给一个expression String, 要evaluate这个expression的值.
+
+Expression string 里面包括 +, -, 整数, 开合括号, 还有space.
+
+#### Expression Tree
+- Expression Tree是一个 weight-based的 min-tree
+- 基于 运算符号 + 数字的 tree: 数字永远在leaf, 然后符号是tree node, 括号不出现在tree里面
+- 用 monotonuous stack 来构建这个tree
+
+##### Thinking points
+- Understand Expression Tree
+- Use stack to build the expression tree + understand the weight system
+- Use post-order traversal to evaluate the tree
+- 注意, input里面的数字不会是single digit, 所以需要一个buffer存number string
+- 整个题目的做法, 可以参照 `Expression Evaluation`
+
+```
+/*
+Implement a basic calculator to evaluate a simple expression string.
+
+The expression string may contain open ( and closing parentheses ),
+the plus + or minus sign -, non-negative integers and empty spaces .
+
+You may assume that the given expression is always valid.
+
+Some examples:
+"1 + 1" = 2
+" 2-1 + 2 " = 3
+"(1+(4+5+2)-3)+(6+8)" = 23
+Note: Do not use the eval built-in library function.
+
+*/
+
+/*
+build expression tree to evaluate expression
+two functions:
+1. build tree
+ parse string
+ skip space
+ identify operator
+ calculate weight of operator
+ add parentheses to base weight
+2. evaluate with post-order traversal
+*/
+class Solution {
+ class TreeNode {
+ int weight;
+ String str;
+ TreeNode left, right;
+ public TreeNode(int weight, String str) {
+ this.weight = weight;
+ this.str = str;
+ }
+ }
+
+ public int calculate(String s) {
+ if (s == null || s.length() == 0) return 0;
+ TreeNode root = buildTree(s); // build expression tree
+ return (int)evaluate(root); // post-order traversal of the tree
+ }
+
+ // build tree based on input string, min-tree. return root
+ private TreeNode buildTree(String s) {
+ int n = s.length();
+ char[] chars = s.trim().toCharArray();
+ Stack stack = new Stack<>();
+ int base = 0;
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < n; i++) {
+ char c = chars[i];
+ if (c == ' ') {
+ continue;
+ } else if (c == '(') { // '()' are used to add weight, not stored in tree
+ base = getWeight(base, c);
+ continue;
+ } else if (c == ')') {
+ base = getWeight(base, c);
+ continue;
+ } else if (i < n - 1 && isDigit(chars[i]) && isDigit(chars[i + 1])) { // continue to get remaining of the int
+ sb.append(c);
+ continue;
+ }
+ String str;
+ if (isDigit(c)) {
+ sb.append(c);
+ str = sb.toString();
+ sb.setLength(0); // clean up
+ } else {
+ str = c + "";
+ }
+
+ // use monotonuous stack to build min-tree
+ TreeNode node = new TreeNode(getWeight(base, c), str);
+ while (!stack.isEmpty() && node.weight <= stack.peek().weight) {
+ node.left = stack.pop();
+ }
+ if (!stack.isEmpty()) {
+ stack.peek().right = node;
+ }
+ stack.push(node);
+ }
+ TreeNode root = null;
+ while (!stack.isEmpty()) {
+ root = stack.pop();
+ }
+
+ return root; // it's the root of tree, always a operator
+ }
+
+ // post-order traversal to evaluate the expression
+ private long evaluate(TreeNode root) {
+ if (root == null) return 0;
+ long left = evaluate(root.left);
+ long right = evaluate(root.right);
+ long result = 0;
+ switch(root.str) {
+ case "+":
+ result = left + right;
+ break;
+ case "-":
+ result = left - right;
+ break;
+ case "*":
+ result = left * right;
+ break;
+ case "/":
+ result = left / right;
+ break;
+ default:
+ result = Long.parseLong(root.str);
+ }
+ return result;
+ }
+
+ // get weight of the character. integer weights the most and will be leaf.
+ // Remember to store the result using long
+ private int getWeight(int base, char c) {
+ if (c == '(') return base + 10;
+ if (c == ')') return base - 10;
+ if (c == '+' || c == '-') return base + 1;
+ if (c == '*' || c == '/') return base + 2;
+ return Integer.MAX_VALUE;
+ }
+
+ private boolean isDigit(char c) {
+ return c >= '0' && c <= '9';
+ }
+}
+
+```
diff --git a/Java/Best Time to Buy and Sell Stock II.java b/Java/Best Time to Buy and Sell Stock II.java
old mode 100644
new mode 100755
index 90196d9..f8c6bb5
--- a/Java/Best Time to Buy and Sell Stock II.java
+++ b/Java/Best Time to Buy and Sell Stock II.java
@@ -1,16 +1,131 @@
-找涨幅最大的区间,买卖。
-飞似得涨,到峰顶,就卖。
+E
+1531717353
+tags: Array, Greedy, DP, Sequence DP, Status DP
+time: O(n)
+space: O(1) greedy, O(n) dp
+
+和Stock I 的区别:可以买卖多次,求总和的最大盈利.
+
+#### 几种其他不同的思路:
+- Greedy, 每次有相邻的diff符合profit条件, 就卖了, 最后把所有的diff加在一起. 计算delta, 其实简单粗暴, 也还不错.
+- 如下, 从低谷找peek, sell.
+- DP. (old dp solution BuyOn[], SellOn[])
+- DFS计算所有(timeout).Improvement on DFS -> DP -> calculate sellOn[i] and buyOn[i], and then return buyOn[i]. 有点难想, 但是代码简单, 也是O(n)
+
+#### Greedy
+- 画图, 因为可以无限买卖, 所以只要有上升, 就有profit
+- 所有卖掉的, 平移加起来, 其实就是overall best profit
+- O(n)
+
+#### 找涨幅最大的区间,买卖:
+- 找到低谷,买进:peek = start + 1 时候,就是每次往前走一步;若没有上涨趋势,继续往低谷前进。
+- 涨到峰顶,卖出:一旦有上涨趋势,进一个while loop,涨到底, 再加个profit.
+- profit += prices[peek - 1] - prices[start]; 挺特别的。
+- 当没有上涨趋势时候,peek-1也就是start, 所以这里刚好profit += 0.
+
+#### DP, sequence dp + status
+- 想知道前i天的最大profit, 那么用sequence DP:
+- dp[i]: represents 前i天的最大profit
+- 当天的是否能卖, 取决于昨天是否买进, 也就是 `昨天买了或者卖了的状态`: 加状态, dp[i][0], dp[i][1]
+- `买`的状态 `dp[i][0]` = 1. 今天买入, 昨天卖掉的dp[i-1][1]结果 - price[i]; 2. 今天不买, 跟昨天买的status dp[i-1][0] 结果 比较.
+- `卖`的状态 `dp[i][1]` = 1. 今天卖出, 昨天买进的dp[i-1][0]结果 + price[i]; 2. 今天不卖, 跟昨天卖的status dp[i-1][1] 结果 比较.
+- 注意init:
+- dp[0][0] = dp[0][1] = 0; // 0 days,
+- dp[1][0] = 0; // sell on 1st day, haven't bought, so just 0 profit.
+- dp[1][0] = -prices[0]; // buy on 1st day, with cost of prices[0]
+
+##### Rolling Array
+- [i] 和 [i - 1] 相关联, roll
+
+
```
/*
Say you have an array for which the ith element is the price of a given stock on day i.
-Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
+Design an algorithm to find the maximum profit. You may complete as many transactions as you like
+(ie, buy one and sell one share of the stock multiple times).
+However, you may not engage in multiple transactions
+at the same time (ie, you must sell the stock before you buy again).
Example
+Given an example [2,1,2,0,1], return 2
+
Tags Expand
-Greedy Array
+Greedy Enumeration Array
+*/
+
+
+/*
+Thoughts:
+Draw a curve and realize that, only when prices[i] > prices[i - 1],
+we complete buy/sell and take the profit.
+Adding more slopes can be greater than 0~N overall height diff.
+
+// Greedy
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int profit = 0;
+ for (int i = 1; i < prices.length; i++) {
+ if (prices[i] > prices[i - 1]) {
+ profit += prices[i] - prices[i - 1];
+ }
+ }
+ return profit;
+ }
+}
+
+//DP: See details at notes above
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int n = prices.length;
+ int[][] dp = new int[n + 1][2];
+ dp[0][0] = dp[0][1] = 0;
+ dp[1][1] = 0;
+ dp[1][0] = - prices[0];// -2
+ for (int i = 2; i <= n; i++) {
+ dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i - 1]);
+ dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i - 1]);
+ }
+ return dp[n][1]; //return Math.max(dp[n][1], dp[n][0]);
+ }
+};
+
+// Rolling array
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int n = prices.length;
+ int[][] dp = new int[2][2];
+ dp[0][0] = dp[0][1] = 0;
+ dp[1][0] = - prices[0];
+ for (int i = 2; i <= n; i++) {
+ dp[i % 2][0] = Math.max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i - 1]);
+ dp[i % 2][1] = Math.max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] + prices[i - 1]);
+ }
+ return dp[n % 2][1];
+ }
+};
+
+
+/*
+Previous notes about the above solution:
+Greedy: when seeing a increase, sell, accumulate the delta benefits.
+For instance, at a inclining slope, the sum of delta changes between (i-1, i) equals to the increase of (0 , n), so it's okay to do greedy.
+But this is less inteligent, and not very applicable
+*/
+
-Thinking process:
+/*
+Thought:
In this case, since we know the entire stock price for all days in the array, we want to this:
Sell it at nearest peek price and buy it on the next dropped price, then sell again at next peek.
Two pointers, start and peek, to track the starting point and the peek.
@@ -19,32 +134,91 @@ Design an algorithm to find the maximum profit. You may complete as many transac
Inner while loop that finds the peek from start.
Note: peek always has index >= start+1.
Sum up all profit and return it.
-Tricky thing: we are looking for max profit, but does not require to sell the stock by end of array. So if the price is dropping, we are not selling and we are not losing/winning anything.
-*/
+Tricky thing: we are looking for max profit, but does not require to sell the stock by end of array.
+So if the price is dropping, we are not selling and we are not losing/winning anything.
+*/
class Solution {
- /**
- * @param prices: Given an integer array
- * @return: Maximum profit
- */
public int maxProfit(int[] prices) {
- if (prices == null || prices.length == 0) {
+ if (prices == null || prices.length <= 1) {
return 0;
}
+ int curr = 0;
int profit = 0;
- int start = 0;
- int peek = 0;
- while (start < prices.length - 1) {
- peek = start + 1;
+ int peek = 1;
+ while(curr < prices.length) {
while (peek < prices.length && prices[peek - 1] <= prices[peek]) {
peek++;
}
- profit += prices[peek - 1] - prices[start];
- start = peek;
+ profit += prices[peek - 1] - prices[curr];
+ curr = peek;
+ peek = curr + 1;
}
return profit;
}
-};
+}
+
+/*
+Thoughts:
+Optimize the DFS (since it times out)
+buyOn[i]: [i ~ n], if buying on day i, what's the best profit
+sellOn[i]: [i ~ n], if selling on day i, what's the best profit.
+equation:
+buyOn[i]: on day i, we can buy && sell on day [i + 1], or do nothing.
+sellOn[i]: on day i, we can sell && buy on day [i + 1], or do nothing.
+buyOn[0]: max value will be calculated and saved up here.
+O(n)
+
+However, still very slow, only beat 2%
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length <= 1) {
+ return 0;
+ }
+ int[] buyOn = new int[prices.length];
+ int[] sellOn = new int[prices.length];
+ int length = prices.length;
+ buyOn[length - 1] = 0;
+ sellOn[length - 1] = prices[length - 1];
+ for (int i = length - 2; i >= 0; i--) {
+ buyOn[i] = Math.max(buyOn[i + 1], sellOn[i + 1] - prices[i]); // (not buying on day i; buying on day i, so - prices[i])
+ sellOn[i] = Math.max(sellOn[i + 1], buyOn[i + 1] + prices[i]);// (not selling on day i; selling on day i, so + prices[i])
+ }
+ return Math.max(0, buyOn[0]);
+ }
+}
+
+
+
+
+/*
+Thoughts:
+On given day: we can choose to buy or sell or move with no action, which generates different paths -> DFS
+However: 196 / 198 test cases passed but times out.
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length <= 1) {
+ return 0;
+ }
+ return Math.max(dfs(prices, 1, true) - prices[0], dfs(prices, 1, false));
+ }
+ private int dfs(int[] prices, int index, boolean sellStatus) {
+ if (index == prices.length - 1) {
+ return sellStatus ? prices[index] : 0;
+ }
+ int profit = 0;
+ for (int i = index; i < prices.length; i++) {
+ //No action
+ profit = Math.max(profit, dfs(prices, i + 1, sellStatus));
+ //Sell or buy:
+ int levelDelta = sellStatus ? prices[i] : - prices[i];
+ profit = Math.max(profit, dfs(prices, i + 1, !sellStatus) + levelDelta);
+ }
+ return profit;
+ }
+}
```
\ No newline at end of file
diff --git a/Java/Best Time to Buy and Sell Stock III.java b/Java/Best Time to Buy and Sell Stock III.java
new file mode 100755
index 0000000..63ad48e
--- /dev/null
+++ b/Java/Best Time to Buy and Sell Stock III.java
@@ -0,0 +1,166 @@
+H
+1523511824
+tags: Array, DP, Sequence DP
+
+比stock II 多了一个限制:只有2次卖出机会.
+
+#### DP加状态
+- 只卖2次, 把买卖分割成5个状态模块.
+- 在状态index 0, 2, 4: 没有持有股票. 1. 一直在此状态, max profit不变; 2. 刚卖掉, dp[i][前状态] + profit
+- 在状态index 1, 3: 持有股票. 1. 一直在此状态, daily profit. 2. 刚刚买进, 状态改变, 但是没有profit yet: dp[i][前状态]
+
+##### Partial profit
+- 把每天的partial profit (diff)加在一起, 最终的overall profit是一样的. 唯一更好的是, 不需要记录中间买入的时间点.
+- 什么时候会积累profit呢?
+- 1. 原本就持有股票的, 如果毫无动作, 那么状态不变, 积累profit diff.
+- 2. 卖出了股票, 状态改变, 积累profit diff.
+- 注意: 只有在状态index: 0, 2, 4, 也就是卖掉股票的时候, 才可以积累profit
+
+##### Rolling Array
+- [i] 只有和 [i-1] 打交道, reduce space
+- O(1) space, O(n) time
+
+#### 找峰头
+- 找峰头;然后往下再找一个峰头。
+- 怎么样在才能Optimize两次巅峰呢?从两边同时开始找Max!(棒棒的想法)
+- leftProfit是从左往右,每个i点上的最大Profit。
+- rightProfit是从i点开始到结尾,每个点上的最大profit.
+- 那么在i点上,就是leftProfit,和右边rightProfit的分割点。在i点,leftProfit+rightProfit相加,找最大值。
+- 三个O(n),还是O(n)
+
+```
+/*
+Say you have an array for which the ith element is the price of a given stock on day i.
+
+Design an algorithm to find the maximum profit. You may complete at most two transactions.
+
+Example
+Given an example [4,4,6,1,1,4,2,5], return 6.
+
+Note
+You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
+
+Tags Expand
+Enumeration Forward-Backward Traversal Array
+
+*/
+/*
+Thoughts:
+DP: calculate the
+Able to sell 2 times. Consider the last position dp[i], is it sold 2 times? sold 1 time? before buying 1st stock? before buying 2nd stock? or right in between 1st and 2nd transaction, having 0 stock?
+The status of the problem should be recorded, which leads to 2nd dimension to record these status:
+0 stock, before buying | having 1st stock | sold 1st stock, having 0, before buying | having 2nd stock| sold 2nd stock
+dp[i][4]: max profit at index i, where both are sold.
+Move the status from 0 ~ 4, and break when reached the end.
+
+equations are a bit complicated:
+- status index 0, 2, 4:
+ dp[i][j]: dp[i - 1][j - 1] + price[i] - price[i - 1] (status changed from yesterday, and profiting)
+ OR: dp[i - 1][j] (status didn't change from yesterday)
+- status index 1, 3
+ dp[i][3]: dp[i - 1][j] + price[i] - prices[i - 1] (status didn't change from yesterday, keep profiting)
+ OR: dp[i - 1][j - 1] (status changed from yesterday, just bought)
+
+init:
+dp[0][0] = 0;
+
+One note:
+Consider incremental profit sum = overall profit sum. Sum of price[i] - price[i - 1] = price[0~N]
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int profit = 0;
+ int n = prices.length;
+ int[][] dp = new int[n][5];
+
+ dp[0][0] = 0; // No transaction on day 0
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < 5; j++) {
+ // Accumulate partial profit regardless of stock status.
+ int dailyDiff = prices[i] - prices[i - 1];
+ if (j % 2 == 0) { // j status: no stock
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + dailyDiff);
+ // Find best profit when not having stock
+ profit = Math.max(profit, dp[i][j]);
+ } else { // j status: have stock
+ dp[i][j] = Math.max(dp[i - 1][j] + dailyDiff, dp[i - 1][j - 1]);
+ }
+ }
+ }
+ return profit;
+ }
+}
+
+// Rolling array
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int profit = 0;
+ int n = prices.length;
+ int[][] dp = new int[2][5];
+
+ dp[0][0] = 0; // No transaction on day 0
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < 5; j++) {
+ // Accumulate partial profit regardless of stock status.
+ int dailyPartialProfit = prices[i] - prices[i - 1];
+ if (j % 2 == 0) { // j status: no stock
+ dp[i % 2][j] = Math.max(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - 1] + dailyPartialProfit);
+ // Find best profit when not having stock
+ profit = Math.max(profit, dp[i % 2][j]);
+ } else { // j status: have stock
+ dp[i % 2][j] = Math.max(dp[(i - 1) % 2][j] + dailyPartialProfit, dp[(i - 1) % 2][j - 1]);
+ }
+ }
+ }
+ return profit;
+ }
+}
+
+/*
+Thoughts:
+Idea from NineChapter: use two arrays to mark max values, however the max values are calculated from left/right sides.
+Left[] marks max profit value in the range from a left-index to current index. Tracking left-min.
+Right[] marks max profit value in the range from current index to a right-index. Tracking right-max.
+If looking at right[i] and left[i] together at index i, they are always representing left-max-profit value and right-max-profit value. Add them together and get results.
+
+*/
+class Solution {
+ /**
+ * @param prices: Given an integer array
+ * @return: Maximum profit
+ */
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int[] leftProfit = new int[prices.length];
+ int[] rightProfit = new int[prices.length];
+ int min = prices[0]; //Default:leftProfit[0] = 0;
+ for (int i = 1; i < prices.length; i++) {
+ min = Math.min(min, prices[i]);
+ leftProfit[i] = Math.max(leftProfit[i - 1], prices[i] - min);
+ }
+ int max = prices[prices.length - 1]; //Default:rightProfit[prices.length - 1] = 0;
+ for (int i = prices.length - 2; i >= 0; i--) {
+ max = Math.max(max, prices[i]);
+ rightProfit[i] = Math.max(rightProfit[i + 1], max - prices[i]);
+ }
+ int profit = 0;
+ for (int i = 0; i < prices.length; i++) {
+ profit = Math.max(profit, leftProfit[i] + rightProfit[i]);
+ }
+ return profit;
+ }
+};
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/Java/Best Time to Buy and Sell Stock IV.java b/Java/Best Time to Buy and Sell Stock IV.java
old mode 100644
new mode 100755
index 56aba94..7702b1f
--- a/Java/Best Time to Buy and Sell Stock IV.java
+++ b/Java/Best Time to Buy and Sell Stock IV.java
@@ -1,6 +1,44 @@
-有问题。还不是非常理解:
-best time to buy and sell stock: 为什么 i-1天的卖了又买,可以和第 i 天的卖合成一次交易?
-因为每天交易的price是定的。所以卖了又买,等于没卖!这就是可以合并的原因。要对价格敏感啊少年。
+H
+1523513634
+tags: DP, Sequence DP
+
+有int[] price of stock, 最多做 k transactions. 求最大profit.
+
+#### DP
+- 根据StockIII, 不难发现StockIV就是把状态划分为2k+1份. 那么同样的代码, 移植.
+
+##### 注意1:
+- 如果k很大, k>n/2, 那么长度为n的数组里面, 最多也只能n/2个transaction
+- 那么题目简化为stockII, 给n数组, 无限次transaction.
+- 注意, status的数量是 2k+1
+- Time O(NK), Space O(2k+1) to store the status
+
+##### 注意2:
+- 最后状态是'没有stock'的都该考虑, 做一个 for 循环比较max.
+- 当然, 来一个profit variable, 不断比较, 也是可以的.
+
+#### 方法2
+- (previous notes, 熟练第一种方法的思考就可以)
+- 记得要理解:为什么 i-1天的卖了又买,可以和第 i 天的卖合成一次交易?
+- 因为每天交易的price是定的。所以卖了又买,等于没卖!这就是可以合并的原因。要对价格敏感啊少年。
+- Inspired from here: http://liangjiabin.com/blog/2015/04/leetcode-best-time-to-buy-and-sell-stock.html
+
+##### 局部最优解 vs. 全局最优解:
+- local[i][j] = max(global[i – 1][j – 1] + diff, local[i – 1][j] + diff)
+- global[i][j] = max(global[i – 1][j], local[i][j])
+- local[i][j]: 第i天,当天一定进行第j次交易的profit
+- global[i][j]: 第i天,总共进行了j次交易的profit.
+
+- local[i][j]和global[i][j]的区别是:local[i][j]意味着在第i天一定有交易(卖出)发生。
+- 当第i天的价格高于第i-1天(即diff > 0)时,那么可以把这次交易(第i-1天买入第i天卖出)跟第i-1天的交易(卖出)合并为一次交易,即local[i][j]=local[i-1][j]+diff;
+- 当第i天的价格不高于第i-1天(即diff<=0)时,那么local[i][j]=global[i-1][j-1]+diff,而由于diff<=0,所以可写成local[i][j]=global[i-1][j-1]。
+- (Note:在我下面这个solution里面没有省去 +diff)
+
+- global[i][j]就是我们所求的前i天最多进行k次交易的最大收益,可分为两种情况:
+- 如果第i天没有交易(卖出),那么global[i][j]=global[i-1][j];
+- 如果第i天有交易(卖出),那么global[i][j]=local[i][j]。
+
+
```
/*
@@ -22,6 +60,144 @@
Dynamic Programming
*/
+
+/*
+Thoughts:
+Similar to StockIII, but able to make k transactions.
+K transactions divides leads to 2K + 1 different status: always have the two conditions 'before buying' and 'holding', plus the final sold status.
+
+Equation:
+on j%2 == 0 days (not having stock):
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + partialProfit);
+on j%2 == 1 days (holding stock)
+ dp[i][j] = Math.max(dp[i - 1][j] + partialProfit, dp[i - 1][j - 1]);
+
+O(n(2*k + 1)) = O(nk)
+space O(nk)
+time O(nk)
+*/
+class Solution {
+ public int maxProfit(int k, int[] prices) {
+ if (prices == null || prices.length == 0 || k <= 0) {
+ return 0;
+ }
+ int profit = 0;
+ int n = prices.length;
+ int statusLength = 2 * k + 1;
+
+ // A side note: if k > n/2, the problem becomes easy: any n/2 number of transactions
+ if (k >= n/2) {
+ for (int i = 1; i < n; i++) {
+ if (prices[i] > prices[i - 1]) {
+ profit += prices[i] - prices[i - 1];
+ }
+ }
+ return profit;
+ }
+
+ int[][] dp = new int[n][statusLength];
+ dp[0][0] = 0; // on day 0, having 0 stock, and with 0 transactions.
+
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < statusLength; j++) {
+ //int partialProfit = prices[i] - prices[i - 1];
+ if (j % 2 == 0) {
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + prices[i] - prices[i - 1]);
+ // Find best profit when not having stock
+ profit = Math.max(profit, dp[i][j]);
+ } else {
+ dp[i][j] = Math.max(dp[i - 1][j] + prices[i] - prices[i - 1], dp[i - 1][j - 1]);
+ }
+ }
+ }
+ return profit;
+ }
+}
+
+// Rolling array with %2
+class Solution {
+ public int maxProfit(int k, int[] prices) {
+ if (prices == null || prices.length == 0 || k <= 0) {
+ return 0;
+ }
+ int profit = 0;
+ int n = prices.length;
+ int statusLength = 2 * k + 1;
+
+ // A side note: if k > n/2, the problem becomes easy: any n/2 number of transactions
+ if (k >= n/2) {
+ for (int i = 1; i < n; i++) {
+ if (prices[i] > prices[i - 1]) {
+ profit += prices[i] - prices[i - 1];
+ }
+ }
+ return profit;
+ }
+
+ int[][] dp = new int[2][statusLength];
+ dp[0][0] = 0; // on day 0, having 0 stock, and with 0 transactions.
+
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < statusLength; j++) {
+ //int partialProfit = prices[i] - prices[i - 1];
+ if (j % 2 == 0) {
+ dp[i % 2][j] = Math.max(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - 1] + prices[i] - prices[i - 1]);
+ // Find best profit when not having stock
+ profit = Math.max(profit, dp[i % 2][j]);
+ } else {
+ dp[i % 2][j] = Math.max(dp[(i - 1) % 2][j] + prices[i] - prices[i - 1], dp[(i - 1) % 2][j - 1]);
+ }
+ }
+ }
+ return profit;
+ }
+}
+
+// optimization: rolling array
+// space: O(k), time: O(nk)
+class Solution {
+ public int maxProfit(int k, int[] prices) {
+ if (prices == null || prices.length == 0 || k <= 0) {
+ return 0;
+ }
+ int profit = 0;
+ int n = prices.length;
+ int statusLength = 2 * k + 1;
+
+ // A side note: if k > n/2, the problem becomes easy: any n/2 number of transactions
+ if (k >= n/2) {
+ for (int i = 1; i < n; i++) {
+ if (prices[i] > prices[i - 1]) {
+ profit += prices[i] - prices[i - 1];
+ }
+ }
+ return profit;
+ }
+
+ int[][] dp = new int[2][statusLength];
+ int prev, curr = 0;
+ dp[0][0] = 0; // on day 0, having 0 stock, and with 0 transactions.
+
+ for (int i = 1; i < n; i++) {
+ // reverse rolling digit
+ prev = curr;
+ curr = 1 - prev;
+ for (int j = 1; j < statusLength; j++) {
+ //int partialProfit = prices[i] - prices[i - 1];
+ if (j % 2 == 0) {
+ dp[curr][j] = Math.max(dp[prev][j], dp[prev][j - 1] + prices[i] - prices[i - 1]);
+ // Find best profit when not having stock
+ profit = Math.max(profit, dp[curr][j]);
+ } else {
+ dp[curr][j] = Math.max(dp[prev][j] + prices[i] - prices[i - 1], dp[prev][j - 1]);
+ }
+ }
+ }
+ return profit;
+ }
+}
+
+
/*
Thoughts: http://liangjiabin.com/blog/2015/04/leetcode-best-time-to-buy-and-sell-stock.html
local[i][j] = max(global[i – 1][j – 1] , local[i – 1][j] + diff). WHY????
@@ -29,11 +205,6 @@
*/
class Solution {
- /**
- * @param k: An integer
- * @param prices: Given an integer array
- * @return: Maximum profit
- */
public int maxProfit(int k, int[] prices) {
if (prices == null || prices.length < 2 || k <= 0) {
return 0;
diff --git a/Java/Best Time to Buy and Sell Stock with Cooldown.java b/Java/Best Time to Buy and Sell Stock with Cooldown.java
new file mode 100644
index 0000000..aba4f58
--- /dev/null
+++ b/Java/Best Time to Buy and Sell Stock with Cooldown.java
@@ -0,0 +1,71 @@
+M
+1518714005
+tags: DP
+
+Sequence DP
+跟StockIII很像. 分析好HaveStock && NoStock的状态, 然后看最后一步.
+
+```
+/*
+Say you have an array for which the ith element is the price of a given stock on day i.
+
+Design an algorithm to find the maximum profit.
+You may complete as many transactions as you like
+(ie, buy one and sell one share of the stock multiple times) with the following restrictions:
+
+You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
+After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
+Example:
+
+prices = [1, 2, 3, 0, 2]
+maxProfit = 3
+transactions = [buy, sell, cooldown, buy, sell]
+*/
+
+/*
+Thoughts:
+Similar to Stock III, where there where 5 states: before1stBuy, have1stStock, soldAndBefore2ndBuy, have2ndStock, soldAll.
+Here we have 3 states:
+BeforeBuy, BuyStock, SoldStock, cooldown(beforeBuy) ====simplify===> HaveStock(buyStock), NoStock(soldStock, cooldown).
+SoldStock and cooldown can be combined together, since there is no stock at hand.
+dp[prices.lengh][2]
+dp[i][j]: at i, what's the best profit under status j
+If j % 2 == haveStock:
+ before (i), no changes, dp[i - 1][j]
+ before (i), bought a stock: dp[i - 1][j] - prices[i - 1];
+
+If j % 2 == noStock
+ before (i), no changes, dp[i - 1][j]
+ before (i), sold stock + cooldown, dp[i - 2][j] + prices[i - 2];
+
+dp[0][0] = 0;
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length <= 1) {
+ return 0;
+ }
+ int n = prices.length;
+ int[][] dp = new int[n][2];
+ dp[0][0] = - prices[0]; //buy
+ dp[0][1] = 0; //sell
+
+ for (int i = 1; i < n; i++) {
+
+ // no stock (sell)
+ dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
+
+ // haveStock (buy)
+ dp[i][0] = dp[i - 1][0];
+ if (i >= 2) {
+ dp[i][0] = Math.max(dp[i][0], dp[i - 2][1] - prices[i]);
+ } else {
+ dp[i][0] = Math.max(dp[i][0], - prices[i]);
+ }
+ //dp[i][0] = Math.max(dp[i - 1][0], (i >= 2 ? dp[i - 2][1] : 0) - prices[i]); // simplify
+ }
+
+ return dp[n - 1][1];
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Best Time to Buy and Sell Stock with Transaction Fee.java b/Java/Best Time to Buy and Sell Stock with Transaction Fee.java
new file mode 100644
index 0000000..9f7cd6d
--- /dev/null
+++ b/Java/Best Time to Buy and Sell Stock with Transaction Fee.java
@@ -0,0 +1,96 @@
+M
+1531728802
+tags: Array, DP, Greedy, Sequence DP, Status DP
+time: O(n)
+space: O(n), O(1) rolling array
+
+跟Stock II 一样, 买卖无限, 需先买在卖. 附加条件: 每个sell transaction要加一笔fee.
+
+#### Sequence DP
+- 与StockII一样, dp[i]: represents 前i天的最大profit.
+- sell 的时候, 才完成了一次transaction, 需要扣fee; 而买入不扣fee.
+- model sell on dp[i] day (which depends on dp[i-1]) and each day can be sell/buy => add status to dp[i][status]
+- status[0] buy on this day, status[1] sell on this day
+- dp[i][0] = Math.max(dp[i-1][0], dp[i - 1][0] - prices[i]);
+- dp[i][1] = Math.max(dp[i-1][1], dp[i - 1][1] + prices[i] - fee);
+- init: dp[0][0,1] = 0; dp[1][1] = 0; dp[1][0] = - prices;
+- return dp[n][1]
+
+```
+/*
+Your are given an array of integers prices,
+for which the i-th element is the price of a given stock on day i;
+and a non-negative integer fee representing a transaction fee.
+
+You may complete as many transactions as you like,
+but you need to pay the transaction fee for each transaction.
+You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.)
+
+Return the maximum profit you can make.
+
+Example 1:
+Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
+Output: 8
+Explanation: The maximum profit can be achieved by:
+Buying at prices[0] = 1
+Selling at prices[3] = 8
+Buying at prices[4] = 4
+Selling at prices[5] = 9
+The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
+Note:
+
+0 < prices.length <= 50000.
+0 < prices[i] < 50000.
+0 <= fee < 50000.
+*/
+
+/*
+- sequence dp. dp[i] represents max profit for first i days.
+- model sell on dp[i] day (which depends on dp[i-1]) and each day can be sell/buy => add status to dp[i][status]
+- status[0] buy on this day, status[1] sell on this day
+- dp[i][0] = Math.max(dp[i-1][0], dp[i - 1][0] - prices[i]);
+- dp[i][1] = Math.max(dp[i-1][1], dp[i - 1][1] + prices[i] - fee);
+- init: dp[0][0,1] = 0; dp[1][1] = 0; dp[1][0] = - prices;
+return dp[n][1]
+*/
+class Solution {
+ public int maxProfit(int[] prices, int fee) {
+ if (prices == null || prices.length <= 1) return 0;
+ // init dp[][] with n+1
+ int n = prices.length;
+ int[][] dp = new int[n + 1][2];
+ dp[0][0] = dp[0][1] = 0;
+ dp[1][1] = 0;
+ dp[1][0] = - prices[0];
+
+ // calculate dp
+ for (int i = 2; i <= n; i++) {
+ dp[i][0] = Math.max(dp[i-1][0], dp[i - 1][1] - prices[i - 1]);
+ dp[i][1] = Math.max(dp[i-1][1], dp[i - 1][0] + prices[i - 1] - fee);
+ }
+
+ return dp[n][1];
+ }
+}
+
+// Rolling array
+class Solution {
+ public int maxProfit(int[] prices, int fee) {
+ if (prices == null || prices.length <= 1) return 0;
+ // init dp[][] with n+1
+ int n = prices.length;
+ int[][] dp = new int[2][2];
+ dp[0][0] = dp[0][1] = 0;
+ dp[1][1] = 0;
+ dp[1][0] = - prices[0];
+
+ // calculate dp
+ for (int i = 2; i <= n; i++) {
+ dp[i%2][0] = Math.max(dp[(i - 1)%2][0], dp[(i - 1)%2][1] - prices[i - 1]);
+ dp[i%2][1] = Math.max(dp[(i - 1)%2][1], dp[(i - 1)%2][0] + prices[i - 1] - fee);
+ }
+
+ return dp[n%2][1];
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Best Time to Buy and Sell Stock.java b/Java/Best Time to Buy and Sell Stock.java
new file mode 100755
index 0000000..eb17d7d
--- /dev/null
+++ b/Java/Best Time to Buy and Sell Stock.java
@@ -0,0 +1,165 @@
+E
+1531717344
+tags: Array, DP, Sequence DP
+
+给个array of stock prices, 限制能交易(买/买)一轮, 问如何找到最大profit.
+
+#### 理解意思是关键
+- 每天都就交易价格,n天只让买卖一次,那就找个最低价买进,找个最高价卖出
+- 记录每天最小值Min是多少. O(n)
+- 每天都算和当下的Min买卖,profit最大多少.
+
+#### DP
+- Find min value for first i items, new dp[n + 1].
+- dp[i]: 前i天, prices最小的price是多少: min cost of first i days
+- 然后用当天的price做减法dp[i]算max profit.
+- Time, Space: O(n)
+- 更进一步, 用一个min来表示min[i], 因为计算中只需要当下的min.
+
+#### Rolling array
+- index i only depend on [i - 2]
+- Space O(n)
+
+#### Brutle Failed
+- 每天都试着买进,然后之后的每一天尝试卖出. double for loop, O(n^2). timeout.
+- 其中很多都是没必要的计算:[7, 1, 5, 3, 6, 4]。 if we know buyin with 1 is cheapest, we don't need to buyin at 5, 3, 6, 4 later on; we'll only sell on higher prices.
+
+```
+/*
+Say you have an array for which the ith element is the price of a given stock on day i.
+
+If you were only permitted to complete at most one transaction
+(ie, buy one and sell one share of the stock),
+design an algorithm to find the maximum profit.
+
+Example 1:
+Input: [7, 1, 5, 3, 6, 4]
+Output: 5
+
+max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)
+Example 2:
+Input: [7, 6, 4, 3, 1]
+Output: 0
+
+In this case, no transaction is done, i.e. max profit = 0.
+
+*/
+
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int n = prices.length;
+ int[] dp = new int[n + 1]; // min value up to first i items
+ dp[0] = Integer.MAX_VALUE;
+ int profit = 0;
+ for (int i = 1; i <= n; i++) {
+ dp[i] = Math.min(dp[i - 1], prices[i - 1]);
+ profit = Math.max(profit, prices[i - 1] - dp[i]);
+ }
+ return profit;
+ }
+}
+
+// Rolling array
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int n = prices.length;
+ int[] dp = new int[2];
+ dp[0] = Integer.MAX_VALUE;
+ int profit = 0;
+ for (int i = 1; i <= n; i++) {
+ dp[i % 2] = Math.min(dp[(i - 1) % 2], prices[i - 1]);
+ profit = Math.max(profit, prices[i - 1] - dp[i % 2]);
+ }
+ return profit;
+ }
+}
+
+/*
+Thoughts:
+Brutle - buy in on any given day (or not buy), and try to sell on any later days; find the max profit; but it timesout.
+
+Lots of calculations are redundant: for example, if we know buyin with 1 is cheapest, we don't need to buyin at 5, 3, 6, 4 later on; we'll only sell on higher prices.
+How about storing the min[i]all the time?
+min[i]: from 0 ~ i the minimum
+Goal: find max of (prices[i] - min[i]) that gives best profit.
+*/
+/*
+Thoughts:
+Brutle - buy in on any given day (or not buy), and try to sell on any later days; find the max profit.
+But it timesout
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length <= 1) {
+ return 0;
+ }
+ int profit = 0;
+ int[] min = new int[prices.length];
+ min[0] = prices[0];
+ for (int i = 1; i < prices.length; i++) {
+ min[i] = Math.min(min[i - 1], prices[i]);
+ profit = Math.max(profit, prices[i] - min[i]);
+ }
+ return profit;
+ }
+}
+
+/*
+Improvement: No need to have array, and only find max when needed.
+
+First to understand what this question is asking:
+Each element is a price of the same stock on that specific day. Of course we want to buy in with min-price and sell out with max-price.
+Find the min-price by looping through the array.
+Find the max-profit: price[i] - min-price, which requires a loop through the loop again.
+We put above 2 tasks into one-pass for loop
+
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length <= 1) {
+ return 0;
+ }
+ int profit = 0, min = prices[0];
+ for (int i = 1; i < prices.length; i++) {
+ if (prices[i] < min) {
+ min = prices[i];
+ } else {
+ profit = Math.max(profit, prices[i] - min);
+ }
+ }
+ return profit;
+ }
+}
+
+
+/*
+Thoughts:
+Brutle - buy in on any given day (or not buy), and try to sell on any later days; find the max profit.
+But it timesout.
+*/
+class Solution {
+ public int maxProfit(int[] prices) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+ int max = 0;
+ for (int i = 0; i < prices.length; i++) {
+ for (int j = i + 1; j < prices.length; j++) {
+ if (prices[j] > prices[i]) {
+ max = Math.max(max, prices[j] - prices[i]);
+ }
+ }
+ }
+ return max;
+ }
+}
+
+
+
+```
\ No newline at end of file
diff --git a/Java/Binary Gap.java b/Java/Binary Gap.java
new file mode 100644
index 0000000..307dc9c
--- /dev/null
+++ b/Java/Binary Gap.java
@@ -0,0 +1,77 @@
+E
+1531623482
+tags: Bit Manipulation
+time: O(n), n = # of bits
+space: O(1)
+
+#### Bit Manipulation
+- 理解Binary Gap的描述
+- 简单的 `>>`, `&1`, track start and end point 就好了
+
+```
+/*
+Given a positive integer N, find and return the longest distance
+between two consecutive 1's in the binary representation of N.
+
+If there aren't two consecutive 1's, return 0.
+
+
+
+Example 1:
+
+Input: 22
+Output: 2
+Explanation:
+22 in binary is 0b10110.
+In the binary representation of 22, there are three ones, and two consecutive pairs of 1's.
+The first consecutive pair of 1's have distance 2.
+The second consecutive pair of 1's have distance 1.
+The answer is the largest of these two distances, which is 2.
+Example 2:
+
+Input: 5
+Output: 2
+Explanation:
+5 in binary is 0b101.
+Example 3:
+
+Input: 6
+Output: 1
+Explanation:
+6 in binary is 0b110.
+Example 4:
+
+Input: 8
+Output: 0
+Explanation:
+8 in binary is 0b1000.
+There aren't any consecutive pairs of 1's in the binary representation of 8, so we return 0.
+
+Note:
+
+1 <= N <= 10^9
+*/
+
+
+
+class Solution {
+ public int binaryGap(int N) {
+ if (N <= 0) return 0;
+ // mark start, end, max
+ int max = 0, start = -1, end = 0;
+ // iterate until N is over
+ while (N > 0) {
+ if ((N & 1) == 1) {
+ if (start == -1) start = end;
+ else {
+ max = Math.max(max, end - start);
+ start = end;
+ }
+ }
+ end++;
+ N = N >> 1;
+ }
+ return max;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/Binary Representation.java b/Java/Binary Representation.java
old mode 100644
new mode 100755
index 3db457d..92112cc
--- a/Java/Binary Representation.java
+++ b/Java/Binary Representation.java
@@ -1,19 +1,26 @@
-主要就是要分两半。
+H
+1529478003
+tags: String, Bit Manipulation
-Integer那一半好弄,Loop里面 num%2, num/2就好。
-Decimal那边复杂点,bit == 1的数学条件是:
-当下num * 2 - 1 >= 0...
-然后循环时候还要 num * 2 - 1, 或者 num * 2
+#### String
+- 首先要分两半解决,断点是'.': str.split("\\.");
+- Integer那一半好弄,whie loop里: num%2, num/2. 做一个 `parseInteger()` function
+- Decimal那边复杂点. 做一个 `parseDecimal()` function:
+- bit == 1的数学条件: 当下num * 2 >= 1。 更新: num = num * 2 - 1;
+- bit == 0的数学条件: num * 2 < 1. 更新: num = num * 2
-因为num是 double, 小于0的小数,所以其实这样做下去很可能无限循环。
-
-所以题目也才有了32BIT的要求!
+#### 注意
+- num是 double, 小数在 `num = num * 2 - 1` 的公式下可能无限循环
+- 因此check: num重复性,以及binary code < 32 bit.
+- 所以题目也才有了32BIT的要求!
```
/*
-Given a (decimal - e.g. 3.72) number that is passed in as a string, return the binary representation that is passed in as a string. If the fractional part of the number can not be represented accurately in binary with at most 32 characters, return ERROR.
+Given a (decimal - e.g. 3.72) number that is passed in as a string,
+return the binary representation that is passed in as a string.
+If the fractional part of the number can not be represented
+accurately in binary with at most 32 characters, return ERROR.
-Have you met this question in a real interview? Yes
Example
For n = "3.72", return "ERROR".
@@ -43,11 +50,8 @@ Given a (decimal - e.g. 3.72) number that is passed in as a string, return the b
for example: 2x - 1 = x -> x = 1. that will cause infinite loop.
*/
+
public class Solution {
- /**
- *@param n: Given a decimal number that is passed in as a string
- *@return: A string
- */
public String binaryRepresentation(String n) {
if (n.length() == 0 || n.equals("0")) {
return "0";
@@ -77,12 +81,12 @@ public String parseInteger(String n) {
return n;
}
int num = Integer.parseInt(n);
- String rst = "";
+ StringBuffer sb = new StringBuffer();
while (num != 0) {
- rst = num % 2 + rst;//mod(2) -> binary representation
+ sb.insert(0, num % 2);//mod(2) -> binary representation
num = num / 2;//小时候转换二进制也是这样。
}
- return rst;
+ return sb.toString();
}
// A little bit math, but implemtable.
public String parseDecimal(String n) {
@@ -92,23 +96,23 @@ public String parseDecimal(String n) {
//A doublem must be able to catch it. If not, that is way bigger than 32 bit.
double num = Double.parseDouble("0." + n);
//Check existance
- HashSet set = new HashSet();
- String rst = "";
+ HashSet set = new HashSet<>();
+ StringBuffer sb = new StringBuffer();
while (num > 0) {
- if (rst.length() > 32 || set.contains(num)) {
+ if (sb.length() > 32 || set.contains(num)) {
return "ERROR";
}
set.add(num);
//For decimal: binary code on one spot == 1, means: num * 2 - 1 > 0
if (num * 2 >= 1) {
- rst = rst + "1";
+ sb.append("1");
num = num * 2 - 1;
} else {
- rst = rst + "0";
+ sb.append("0");
num = num * 2;
}
}
- return rst;
+ return sb.toString();
}
}
```
\ No newline at end of file
diff --git a/Java/Binary Search Tree Iterator.java b/Java/Binary Search Tree Iterator.java
old mode 100644
new mode 100755
index 0333f5a..6c2bd31
--- a/Java/Binary Search Tree Iterator.java
+++ b/Java/Binary Search Tree Iterator.java
@@ -1,17 +1,47 @@
-理解binary search tree inorder traversal的规律。
-都是先找left.left.left ....left. 为top。
-然后再找parent,然后再right.
+M
+1518626557
+tags: Stack, Tree, Design, BST
+
+画一下, BST in order traversal. 用stack记录最小值, 放在top. O(h) space.
+每次消耗TreeNode, 都看看rightNode(其实就是下一个最小的candidate), 并且一条龙stack叠上rightNode所有的left子孙.
+
+Previous Notes:
+用O(h)空间的做法:
+
+理解binary search tree inorder traversal的规律:
+ 先找left.left.left ....left 到底,这里是加进stack.
+ 然后考虑parent,然后再right.
+
+例如这题:
+ stack里面top,也就是tree最左下角的node先考虑,取名rst.
+ 其实这个rst拿出来以后, 它也同时是最底层left null的parent,算考虑过了最底层的parent。
+ 最后就考虑最底层的parent.right, 也就是rst.right.
+
+注意:
+ next()其实有个while loop, 很可能是O(h).题目要求average O(1),所以也是okay的.
+
+
+用O(1)空间的做法:不存stack, 时刻update current为最小值。
+
+找下一个最小值,如果current有right child:
+ 和用stack时的iteration类似,那么再找一遍current.right的left-most child,就是最小值了。
+
+如果current没有right child:
+ 那么就要找current node的右上parent, search in BinarySearchTree from root.
+
+注意:
+ 一定要确保找到的parent满足parent.left == current.
+ 反而言之,如果current是parent的 right child, 那么下一轮就会重新process parent。
+ 但是有错:binary search tree里面parent是小于right child的,也就是在之前一步肯定visit过,如此便会死循环。
+
-这个题目里面找到rst之后,首先考虑这个rst.right
- 其实rst在这里虽然是most left node, 但对于rst.right来说,其实它也是parent.
-所以每次把left全部弄一边的时候,parent node其实也都是顾及到了的。
```
/*
Design an iterator over a binary search tree with the following rules:
Elements are visited in ascending order (i.e. an in-order traversal)
next() and hasNext() queries run in O(1) time in average.
-Have you met this question in a real interview? Yes
+
Example
For the following binary search tree, in-order traversal by using iterator is [1, 6, 10, 11, 12]
@@ -29,14 +59,6 @@ Extra memory usage O(h), h is the height of the tree.
Binary Tree LintCode Copyright Non Recursion Binary Search Tree Google LinkedIn Facebook
*/
-/*
- Thoughts://http://blog.csdn.net/u014748614/article/details/46800891
- Put all left nodes into stack. Then top of stack must be the first element in in-order-traversal.
- We never add right node into stack directly, but ever time before returnning the rst node, we take care of rst.right right away.
- That is, find next() when rst.right as root.
- very smart use of a 'currnt' node.
- It's like a pointer on the tree, but only operates when that current node is not null, and under condition of having left child.
-*/
/**
* Definition of TreeNode:
@@ -55,6 +77,95 @@ That is, find next() when rst.right as root.
* do something for node
* }
*/
+
+ /*
+Thoughts:
+Inorder traversal, always having the smallest on top.
+Use stack to keep smallest item on top of stack; when consuming an item, always find right, and dive in and stack most left children
+*/
+public class BSTIterator {
+ final Stack stack = new Stack<>();
+ public BSTIterator(TreeNode root) {
+ if (root == null) {
+ return;
+ }
+ TreeNode node = root;
+ while (node != null) {
+ stack.push(node);
+ node = node.left;
+ }
+ }
+
+ /** @return whether we have a next smallest number */
+ public boolean hasNext() {
+ return !stack.isEmpty();
+ }
+
+ /** @return the next smallest number */
+ public int next() {
+ TreeNode rst = stack.pop();
+ if (rst.right != null) {
+ TreeNode node = rst.right;
+ while(node != null) {
+ stack.push(node);
+ node = node.left;
+ }
+ }
+ return rst.val;
+ }
+}
+
+//Recap 02.24.2016: Similar to solution below. O(h) space.
+//Stack, inorder traversal; first add left node till end. Each next() trigger a iteration.
+public class BSTIterator {
+ public Stack stack = new Stack();
+
+ //@param root: The root of binary tree.
+ //Add till end of left
+ public BSTIterator(TreeNode root) {
+ if (root == null) {
+ return;
+ }
+ stack.push(root);
+ while (root.left != null) {
+ stack.push(root.left);
+ root = root.left;
+ }
+ }
+
+ //@return: True if there has next node, or false
+ public boolean hasNext() {
+ return stack.size() > 0;
+ }
+
+ //@return: return next node
+ public TreeNode next() {
+ TreeNode node = stack.pop();
+ if (node.right != null) {
+ TreeNode temp = node.right;
+ stack.push(temp);
+ while (temp.left != null) {
+ stack.push(temp.left);
+ temp = temp.left;
+ }
+ }
+ return node;
+ }
+}
+
+
+
+/*
+ Previous correct implementation, O(h) space.
+ Thoughts:http://blog.csdn.net/u014748614/article/details/46800891
+ Put all left nodes into stack. Then top of stack must be the first element in in-order-traversal.
+ We never add right node into stack directly, but ever time before returnning the rst node, we take care of rst.right right away.
+ That is, find next() when rst.right as root.
+ very smart use of a 'currnt' node.
+ It's like a pointer on the tree, but only operates when that current node is not null, and under condition of having left child.
+
+*/
+
public class BSTIterator {
public Stack stack = new Stack();
public TreeNode current;
@@ -80,13 +191,95 @@ public TreeNode next() {
}
}
+/*
+ Use O(1) space, which means we will not use O(h) stack.
+ To begin:
+ 1. hasNext()? current.val <= endNode.val to check if the tree is fully traversed.
+ 2. Find min via left-most: We can alwasy look for left-most to find next minimum value.
+
+ 3. Once left-most min is checked (name it `current`). Next min will be 2 cases:
+ If current.right != null, we can keep looking for current.right's left-most child, as next min.
+ Or, we need to look backwards for parent. Use binary search tree to find current's parent node.
+
+ Note: when doing binary search for parent, make sure it satisfies parent.left = current.
+
+ Because:If parent.right == current, that parent must has been visited before. In binary search tree,
+ we know that parent.val < parent.right.val. We need to skip this special case, since it leads
+ to ifinite loop.
+*/
+
+
+public class BSTIterator {
+ public TreeNode root;
+ public TreeNode current;
+ public TreeNode endNode;
+ //@param root: The root of binary tree.
+ public BSTIterator(TreeNode root) {
+ if (root == null) {
+ return;
+ }
+ this.root = root;
+ this.current = root;
+ this.endNode = root;
+
+ while (endNode != null && endNode.right != null) {
+ endNode = endNode.right;
+ }
+ while (current != null && current.left != null) {
+ current = current.left;
+ }
+ }
+
+ //@return: True if there has next node, or false
+ public boolean hasNext() {
+ return current != null && current.val <= endNode.val;
+ }
+
+ //@return: return next node
+ public TreeNode next() {
+ TreeNode rst = current;
+ //current node has right child
+ if (current.right != null) {
+ current = current.right;
+ while (current.left != null) {
+ current = current.left;
+ }
+ } else {//Current node does not have right child.
+ current = findParent();
+ }
+ return rst;
+ }
+
+ //Find current's parent, where parent.left == current.
+ public TreeNode findParent(){
+ TreeNode node = root;
+ TreeNode parent = null;
+ int val = current.val;
+ if (val == endNode.val) {
+ return null;
+ }
+ while (node != null) {
+ if (val < node.val) {
+ parent = node;
+ node = node.left;
+ } else if (val > node.val) {
+ node = node.right;
+ } else {//node.val == current.val
+ break;
+ }
+ }
+ return parent;
+ }
+}
+
+
+```
-```
\ No newline at end of file
diff --git a/Java/Binary Search.java b/Java/Binary Search.java
deleted file mode 100644
index 5931e4a..0000000
--- a/Java/Binary Search.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-Easy Binary Search Show Result My Submissions
-
-26% Accepted
-Binary search is a famous question in algorithm.
-
-For a given sorted array (ascending order) and a target number, find the first index of this number in O(log n) time complexity.
-
-If the target number does not exist in the array, return -1.
-
-Example
-If the array is [1, 2, 3, 3, 4, 5, 10], for given target 3, return 2.
-
-Challenge
-If the count of numbers is bigger than MAXINT, can your code work properly?
-
-Tags Expand
-Binary Search
-
--
-*/
-
-class Solution {
- /**
- * @param nums: The integer array.
- * @param target: Target to find.
- * @return: The first position of target. Position starts from 0.
- */
- public int binarySearch(int[] nums, int target) {
- //write your code here
- if (nums.length == 0) {
- return -1;
- }
-
- int start = 0;
- int end = nums.length - 1;
- int mid;
-
- while (start + 1 < end) {
- mid = start + (end - start) / 2;
- if (nums[mid] < target) {
- start = mid;
- } else if (nums[mid] > target) {
- end = mid;
- } else {
- end = mid;
- }
- }
-
- if (nums[start] == target) {
- return start;
- } else if (nums[end] == target) {
- return end;
- } else {
- return -1;
- }
- }
-
-
-}
-
diff --git a/Java/Binary Tree Inorder Traversal.java b/Java/Binary Tree Inorder Traversal.java
old mode 100644
new mode 100755
index c53c3e8..adb7668
--- a/Java/Binary Tree Inorder Traversal.java
+++ b/Java/Binary Tree Inorder Traversal.java
@@ -1,19 +1,30 @@
-1. Recursive: Divide and Conquer
-2. Stack: add left nodes all the way; then print curr; move to right, add right if possible.
-3. Recursive with helper method
+E
+1521646879
+tags: Hash Table, Stack, Tree
+Inorder traverse Binary Tree
-注意inorder traversal在check right node的事后,
-不论right == null or != null, 每次都要强行move to right.
+#### Recursive
+- 在自己的基础上recursive, 不用helper function
+- Divide and Conquer, with helper(dfs) method
+- O(n) time, no extra space
-如果不node = node.right,
-很可能发生窘境:
-node alays = stack.top(), 然后stack.top()一直是一开始把left 全部遍历的内容。所以就会infinite loop, 永远在左边上下上下。
+#### Iterative: Stack
+- Add left nodes all the way
+- Print curr
+- Move to right, add right if possible
+- O(n) time, O(h) space
+
+注意stack.pop()在加完left-most child 的后,一定要curr = curr.right.
+若不右移, 很可能发生窘境:
+curr下一轮还是去找自己的left-most child,不断重复curr and curr.left, 会infinite loop, 永远在左边上下上下。
+
+#### HashMap
+? How?
```
/*
-Binary Tree Inorder Traversal
Given a binary tree, return the inorder traversal of its nodes' values.
Example
@@ -32,12 +43,104 @@
Can you do it without recursion?
Tags Expand
-Binary Tree
+Recursion Binary Tree Binary Tree Traversal
+
+*/
+
+/*
+Thoughts:
+Recursive, append left, itself, then right
+*/
+class Solution {
+ public List inorderTraversal(TreeNode root) {
+ List rst = new ArrayList<>();
+ if (root == null) {
+ return rst;
+ }
+ if (root.left == null && root.right == null) {
+ rst.add(root.val);
+ return rst;
+ }
+ List left = inorderTraversal(root.left);
+ List right = inorderTraversal(root.right);
+
+ rst.addAll(left);
+ rst.add(root.val);
+ rst.addAll(right);
+ return rst;
+ }
+}
+
+/*
+ recap 3.15.2016
+ Recursive
+*/
+public class Solution {
+ public List inorderTraversal(TreeNode root) {
+ List rst = new ArrayList();
+ if (root == null) {
+ return rst;
+ }
+ dfs(rst, root);
+ return rst;
+ }
+
+ public void dfs(List rst, TreeNode node) {
+ if (node.left != null) {
+ dfs(rst, node.left);
+ }
+ rst.add(node.val);
+ if (node.right != null) {
+ dfs(rst, node.right);
+ }
+ }
+}
+
+
+/*
+Thoughts:
+Iterative
+Stack, always treat left-most-leaf with priority
+- add node.left till end.
+- consume stack.pop()
+- if has right, add node.right and push all left children to stack
*/
+class Solution {
+ public List inorderTraversal(TreeNode root) {
+ List rst = new ArrayList<>();
+ if (root == null) {
+ return rst;
+ }
+ Stack stack = new Stack<>();
+ TreeNode node = root;
+ // Dive deep to left-most leaf
+ while (node != null) {
+ stack.push(node);
+ node = node.left;
+ }
+
+ while (!stack.isEmpty()) {
+ // Add to rst
+ node = stack.pop();
+ rst.add(node.val);
+ // Add node.right and all left children
+ if (node.right != null) {
+ node = node.right;
+ while (node != null) {
+ stack.push(node);
+ node = node.left;
+ }
+ }
+ }
+ return rst;
+ }
+}
+
+// Previous notes
/*
- 3. Use a helper method, recursively add to rst
+ 1. Use a helper method, recursively add to rst
*/
public class Solution {
@@ -78,10 +181,6 @@ public void helper(ArrayList rst, TreeNode node) {
*/
public class Solution {
- /**
- * @param root: The root of binary tree.
- * @return: Inorder in ArrayList which contains node values.
- */
public ArrayList inorderTraversal(TreeNode root) {
ArrayList rst = new ArrayList();
if (root == null) {
@@ -99,7 +198,7 @@ public ArrayList inorderTraversal(TreeNode root) {
//Pop the top node: the curr node
curr = stack.pop();
rst.add(curr.val);
- //Move to right node, and push to satck if needed
+ //Move to right node, and push to stack if needed
curr = curr.right;
if (curr!= null) {
stack.push(curr);
@@ -110,66 +209,7 @@ public ArrayList inorderTraversal(TreeNode root) {
}
-/*
-Thinking process:
-1. Use recursive function: divide and conquer
- recursive on left
- result.add( current.val)
- recursive on right
-2. Use Stack to do traversal
- while stack not empty {
- stack all left childs
- result.(current.val)
- stack 1 right child
- }
-*/
-public class Solution {
-
- //Recursive - Divide and Conquer
- public ArrayList inorderTraversal(TreeNode root) {
- ArrayList rst = new ArrayList();
- if (root == null) {
- return rst;
- }
- inorderRec(rst, root);
- return rst;
- }
- public void inorderRec(ArrayList rst, TreeNode root) {
- if (root == null) {
- return;
- }
- inorderRec(rst, root.left);
- rst.add(root.val);
- inorderRec(rst, root.right);
- }
- //Traversal using Stack
- public ArrayList inorderTraversal(TreeNode root) {
- ArrayList rst = new ArrayList();
- if (root == null) {
- return rst;
- }
- Stack stack = new Stack();
- TreeNode curr = root;
- stack.push(curr);
- while (!stack.empty()) {
- while (curr != null && curr.left != null) {
- curr = curr.left;
- stack.push(curr);
- }
- curr = stack.pop();
- rst.add(curr.val);
- curr = curr.right;
- if (curr != null) {
- stack.push(curr);
- }
- }
- return rst;
- }
-
-
-
-}
```
\ No newline at end of file
diff --git a/Java/Binary Tree Level Order Traversal II.java b/Java/Binary Tree Level Order Traversal II.java
old mode 100644
new mode 100755
index ae360e1..bd496ba
--- a/Java/Binary Tree Level Order Traversal II.java
+++ b/Java/Binary Tree Level Order Traversal II.java
@@ -1,5 +1,22 @@
+M
+1526453488
+tags: Tree, BFS
+
+如题, 但是output要倒序.
+
+#### BFS
+- 跟Binary Tree Level Order Traversal一样,只不过存result一直存在存在0位.
+
+
+#### DFS
+- 根据level来append每个list
+- rst里面add(0,...)每次都add在list开头
+
+```
+
/*
-Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).
+Given a binary tree, return the bottom-up level order traversal of its nodes' values.
+(ie, from left to right, level by level from leaf to root).
Example
Given binary tree {3,9,20,#,#,15,7},
@@ -19,17 +36,38 @@
[3]
]
Tags Expand
-Tree Search Breadth First Search Queue Binary Tree
-
-
-Thinking Process:
-1. Non-recursive
-similar to Binary Tree Level Order Traversal I, just when adding into the final result, add to the top all the time. Then the first added will be at the bottom: result.add(0, list)
-2. Recursive:
- Similar to Level Traversal I, do a dfs. The difference is: everytime, we use ArrayList> like a stack by doing add(0, newList);
- when populating the levelArrayList, make sure to address the correct corresponding level.
+Queue Binary Tree Binary Tree Traversal Breadth First Search
*/
+class Solution {
+ public List> levelOrderBottom(TreeNode root) {
+ ArrayList> result = new ArrayList<>();
+ if (root == null) {
+ return result;
+ }
+ Queue queue = new LinkedList<>();
+ queue.offer(root);
+
+ while (!queue.isEmpty()) {
+ final ArrayList list = new ArrayList<>();
+ int size = queue.size();
+ for (int i = 0; i < size; i++) {
+ final TreeNode node = queue.poll();
+ list.add(node.val);
+ if (node.left != null) {
+ queue.offer(node.left);
+ }
+ if (node.right != null) {
+ queue.offer(node.right);
+ }
+ }
+ result.add(0, list);
+ }// end while
+
+ return result;
+ }
+}
+
/**
* Definition of TreeNode:
* public class TreeNode {
@@ -41,8 +79,93 @@
* }
* }
*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+class Solution {
+ public List> levelOrderBottom(TreeNode root) {
+ ArrayList> result = new ArrayList<>();
+ if (root == null) {
+ return result;
+ }
+ Queue queue = new LinkedList<>();
+ queue.offer(root);
+
+ while (!queue.isEmpty()) {
+ final ArrayList list = new ArrayList<>();
+ int size = queue.size();
+ for (int i = 0; i < size; i++) {
+ final TreeNode node = queue.poll();
+ list.add(node.val);
+ if (node.left != null) {
+ queue.offer(node.left);
+ }
+ if (node.right != null) {
+ queue.offer(node.right);
+ }
+ }
+ result.add(0, list);
+ }// end while
+
+ return result;
+ }
+}
+
+/*
+Thoughts:
+Breadth first traversal. Add to 0 position every time.
+BFS uses a queue for level -> traversal completes when the queue is drained.
+Use another queue to store next level, and switch with current queue when need to be.
+*/
+class Solution {
+ public List> levelOrderBottom(TreeNode root) {
+ final List> result = new ArrayList>();
+ if (root == null) {
+ return result;
+ }
+ Queue queue = new LinkedList<>();
+ Queue queueLevel = new LinkedList<>();
+ List level = new ArrayList<>();
+ queue.add(root);
+ while(!queue.isEmpty()) {
+ final TreeNode node = queue.poll();
+ level.add(node.val);
+ if (node.left != null) {
+ queueLevel.add(node.left);
+ }
+ if (node.right != null) {
+ queueLevel.add(node.right);
+ }
+ if (queue.isEmpty()) {
+ queue = queueLevel;
+ result.add(0, level);
+ queueLevel = new LinkedList<>();
+ level = new ArrayList<>();
+ }
+ }
+ return result;
+ }
+}
-
+ /*
+
+Thoughts:
+1. Non-recursive
+similar to Binary Tree Level Order Traversal I, just when adding into the final result,
+add to the top all the time. Then the first added will be at the bottom: result.add(0, list)
+2. Recursive:
+ Similar to Level Traversal I, do a dfs. The difference is: everytime, we use ArrayList> like a stack by doing add(0, newList);
+ when populating the levelArrayList, make sure to address the correct corresponding level.
+
+ */
+
public class Solution {
/**
* @param root: The root of binary tree.
@@ -89,3 +212,4 @@ public void dfs(TreeNode root, int level, ArrayList> rst) {
}
}
+```
diff --git a/Java/Binary Tree Level Order Traversal.java b/Java/Binary Tree Level Order Traversal.java
old mode 100644
new mode 100755
index 8cdb741..94ebd78
--- a/Java/Binary Tree Level Order Traversal.java
+++ b/Java/Binary Tree Level Order Traversal.java
@@ -1,10 +1,23 @@
-1. 最普通,Non-recursive: bfs, queue
-2. Recursive with dfs: use a level to track. Add curr into corresponding level; each level > rst.size(), add a new [].
- Note: rst is a ArrayList>, where each level is a arraylist; that is why we can add [] into rst to represent a level.
+M
+1526453393
+tags: Tree, BFS, DFS
+
+如题.
+
+#### BFS
+- 最普通,Non-recursive: BFS, queue, 用个queue.size()来end for loop:换行。
+- 或者用两个queue. 当常规queue empty,把backup queue贴上去
+
+#### DFS
+- 每个level都应该有个ArrayList. 那么用一个int level来查看:是否每一层都有了相应的ArrayList。
+- 如果没有,就加上一层。
+- 之后每次都通过DFS在相应的level上面加数字。
+
+
```
/*
-34% Accepted
-Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
+Given a binary tree, return the level order traversal of its nodes' values.
+(ie, from left to right, level by level).
Example
Given binary tree {3,9,20,#,#,15,7},
@@ -24,21 +37,13 @@
[15,7]
]
Challenge
-Using only 1 queue to implement it.
+Challenge 1: Using only 1 queue to implement it.
+
+Challenge 2: Use DFS algorithm to do it.
Tags Expand
-Tree Search Breadth First Search Queue Binary Tree
+Queue Binary Tree Breadth First Search Binary Tree Traversal Uber LinkedIn Facebook
-Thinking process:
-1. Non-recursive
-Use queue to withhold the parent.
-Poll one parent, add this parent’s value to arrayList
-Add the children into Arraylist
-jump to next level
-2. Recursive
-use a integer to track levels.
-If at a new level, then create a new ArrayList.
-At each node, add the node to corresponding level-ArrayList
*/
/**
@@ -52,7 +57,46 @@
* }
* }
*/
-
+
+public class Solution {
+ public List> levelOrder(TreeNode root) {
+ List> rst = new ArrayList<>();
+ if (root == null) {
+ return rst;
+ }
+ Queue queue = new LinkedList<>();
+ queue.offer(root);
+ while (!queue.isEmpty()) {
+ int size = queue.size();
+ List list = new ArrayList<>();
+ while (size > 0) {
+ size--;
+ TreeNode node = queue.poll();
+ list.add(node.val);
+ if(node.left != null) queue.offer(node.left);
+ if(node.right != null) queue.offer(node.right);
+ }
+ rst.add(list);
+ }
+ return rst;
+ }
+}
+
+/*
+Thoughts:
+1. Non-recursive
+Use queue to withhold the parent.
+Poll one parent, add this parent’s value to arrayList
+Add the children into Arraylist
+jump to next level
+2. Recursive
+use a integer to track levels.
+If at a new level, then create a new ArrayList.
+At each node, add the node to corresponding level-ArrayList
+*/
+
+//Non-recurive Iterative way:
+//Even with while + for nested loop, it's just O(n)
public class Solution {
/**
* @param root: The root of binary tree.
@@ -63,7 +107,7 @@ public ArrayList> levelOrder(TreeNode root) {
if (root == null) {
return result;
}
- /* //Non-recurive Iterative way:
+
//Use a queue to list elements: each row
Queue queue = new LinkedList();
queue.offer(root);
@@ -83,9 +127,58 @@ public ArrayList> levelOrder(TreeNode root) {
}
result.add(list);
}//while
- */
+
+ return result;
+ }
+}
+
+//Another Iterative way: using 2 Queues
+public class Solution {
+ public List> levelOrder(TreeNode root) {
+ List> rst = new ArrayList>();
+ if (root == null) {
+ return rst;
+ }
+ Queue queue = new LinkedList();
+ Queue backQueue = new LinkedList();
+ queue.offer(root);
+ ArrayList list = new ArrayList();
+
+ while (!queue.isEmpty()) {
+ TreeNode node = queue.poll();
+ if (node.left != null) {
+ backQueue.offer(node.left);
+ }
+ if (node.right != null) {
+ backQueue.offer(node.right);
+ }
+ list.add(node.val);
+
+ if (queue.isEmpty()) {
+ rst.add(new ArrayList(list));
+ list = new ArrayList();
+ queue = backQueue;
+ backQueue = new LinkedList();
+ }
+
+ }
+ return rst;
+ }
+}
+
+
+
+//Recursive:
+//Recursive with dfs: use a level to track. Add curr into corresponding level; each level > rst.size(), add a new [].
+//Note: rst is a ArrayList>, where each level is a arraylist; that is why we can add [] into rst to represent a level.
+
+public class Solution {
+ public ArrayList> levelOrder(TreeNode root) {
+ ArrayList> result = new ArrayList>();
+ if (root == null) {
+ return result;
+ }
- //Recursive:
dfs(root, 0, result);
return result;
}
diff --git a/Java/Binary Tree Longest Consecutive Sequence II.java b/Java/Binary Tree Longest Consecutive Sequence II.java
new file mode 100644
index 0000000..b37899c
--- /dev/null
+++ b/Java/Binary Tree Longest Consecutive Sequence II.java
@@ -0,0 +1,86 @@
+M
+1526453838
+tags: Tree, DFS, Divide and Conquer, Double Recursive
+
+找到binary tree 里的最长 consecutive sequence. Sequence可以递增递减, Sequence顺序可以回溯parent.
+
+#### DFS, Divide and Conquer
+- Similar to Binary Tree Longest Consecutive Sequence I
+- 只不过可以递增递减, 还有连接上parent的方向.
+- 对于任何一个节点, 都可能:
+- 1. 自己跟两个child链接, 成为一个sequence
+- 2. 左边孩子, 右边孩子各自是一个consecutive sequence, 但是不跟root相连
+- main function 一开始就divide成这三份, 然后dfs
+- dfs take diff == 1, diff == -1, 来做递增递减的校对.
+- dfs rules:
+- 1. if node == null, leaf depth = 0
+- 2. if not consecutive, reset the depth = 0 (same for both left child, and right child)
+- 3. compare the leftDepth && rightDepth to find the maximum
+- 4. diff is the same in the same dfs loop to maintain consistant increase/decrease
+
+##### 注意
+- dfs的结果很可能是0, 如果没有任何结果, 那么上一层的caller depth = dfs() + 1 = 1
+- 那么回归到root, dfs的结果很可能就是1.
+- 可能会问: 那么在tree里面的partial sequence (不连接到root)的被忽略了?
+- 这里 `longestConsecutive(root.left)` 就很重要了
+- 这一步特地忽略掉了root, 然后走下去一层: 因为是recursive, 所以还会继续divde && conquer
+- 最后, 任何一层的孩子都会被照顾到.
+
+##### Double Recursive functions
+- 用两种recursive的方式handle skip root node的情况
+- Recursive using dfs(), basically build child + parent
+- Recursive using main function, but with value of child node: skipping root
+
+```
+/*
+Given a binary tree, you need to find the length of Longest Consecutive Path in Binary Tree.
+
+Especially, this path can be either increasing or decreasing. For example,
+[1,2,3,4] and [4,3,2,1] are both considered valid, but the path [1,2,4,3] is not valid.
+On the other hand, the path can be in the child-Parent-child order,
+where not necessarily be parent-child order.
+
+Example 1:
+Input:
+ 1
+ / \
+ 2 3
+Output: 2
+Explanation: The longest consecutive path is [1, 2] or [2, 1].
+Example 2:
+Input:
+ 2
+ / \
+ 1 3
+Output: 3
+Explanation: The longest consecutive path is [1, 2, 3] or [3, 2, 1].
+Note: All the values of tree nodes are in the range of [-1e7, 1e7].
+*/
+class Solution {
+ public int longestConsecutive (TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+ int result = dfs(root, 1) + dfs(root, -1) + 1;
+ return Math.max(result, Math.max(longestConsecutive(root.left), longestConsecutive(root.right)));
+ }
+
+ // diff can be 1,-1, indicating increasing or decreasing by 1
+ private int dfs(TreeNode node, int diff) {
+ if (node == null) {
+ return 0;
+ }
+ int leftDepth = 0, rightDepth = 0;
+ // check node
+ if (node.left != null && node.val - node.left.val == diff) {
+ leftDepth = dfs(node.left, diff) + 1;
+ }
+ if (node.right != null && node.val - node.right.val == diff) {
+ rightDepth = dfs(node.right, diff) + 1;
+ }
+ return Math.max(leftDepth, rightDepth);
+ }
+}
+
+
+```
\ No newline at end of file
diff --git a/Java/Binary Tree Longest Consecutive Sequence.java b/Java/Binary Tree Longest Consecutive Sequence.java
new file mode 100755
index 0000000..df86818
--- /dev/null
+++ b/Java/Binary Tree Longest Consecutive Sequence.java
@@ -0,0 +1,150 @@
+M
+1527054989
+tags: Tree, DFS, Divide and Conquer
+
+找到binary tree 里的最长 consecutive sequence.
+
+#### DFS
+- Divide and Conquer. dfs
+- 分开 看左边/右边
+- 如果左边满足连续递增的规则, dfs (depth + 1), 如果不满足规则, dfs(depth = 1)
+- 右边也是一样
+- 对结果跟max作比较, return
+
+```
+/*
+Given a binary tree, find the length of the longest consecutive sequence path.
+
+The path refers to any sequence of nodes from some starting node to any node in the tree
+along the parent-child connections. The longest consecutive path need to be from parent to child
+(cannot be the reverse).
+
+For example,
+ 1
+ \\
+ 3
+ / \\
+ 2 4
+ \\
+ 5
+Longest consecutive sequence path is 3-4-5, so return 3.
+ 2
+ \\
+ 3
+ /
+ 2
+ /
+ 1
+Longest consecutive sequence path is 2-3,not3-2-1, so return 2.
+
+Tags:Tree
+Similar Problems: (H) Longest Consecutive Sequence
+
+*/
+/*
+Thoughts:
+1. Mark depth at each level
+2. discuss wether extend or start new depth (per problem requirement)
+*/
+class Solution {
+ public int longestConsecutive (TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+ return dfs(root, 1);
+ }
+
+ private int dfs(TreeNode node, int depth) {
+ if (node == null) {
+ return depth;
+ }
+
+ // check node
+ int leftDepth = (node.left != null && node.val + 1 == node.left.val) ?
+ dfs(node.left, depth + 1) : dfs(node.left, 1);
+ int rightDepth = (node.right != null && node.val + 1 == node.right.val) ?
+ dfs(node.right, depth + 1) : dfs(node.right, 1);
+ return Math.max(depth, Math.max(leftDepth, rightDepth));
+ }
+}
+
+/*
+// DFS, actually find all the items in rst: List>. It's not requried in this problem.
+public class Solution {
+ public int longestConsecutive(TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+ List> rst = new ArrayList<>();
+ dfs(rst, new ArrayList<>(), root);
+ List list = new ArrayList<>();
+ for (List candidate: rst) {
+ list = candidate.size() > list.size() ? candidate : list;
+ }
+ return list.size();
+ }
+
+ private void dfs(List> rst,
+ List list,
+ TreeNode node) {
+ if (node == null) {
+ if (list != null && list.size() > 0) {
+ rst.add(new ArrayList<>(list));
+ }
+ return;
+ }
+
+ // check node
+ if (list.size() > 0 && list.get(list.size() - 1) != node.val - 1) {
+ rst.add(new ArrayList<>(list));
+ dfs(rst, new ArrayList<>(), node);
+ } else {
+ list.add(node.val);
+ dfs(rst, list, node.left);
+ dfs(rst, list, node.right);
+ list.remove(list.size() - 1);
+ }
+ }
+}
+*/
+
+/*
+Attemp2: http://www.cnblogs.com/jcliBlogger/p/4923745.html.
+The original solution has just 4 lines of C++ code. That hurts.
+The concept is very much similar as my attempt1, though the code is more clear with recursive call
+1. pass alone a depth.
+2. if consecutive, depth++; else, start from depth 1
+3. Go deeper on both left, and right; both with new depth: currDepth;
+4. Compare the Max of currDept, left's return, right's return.
+*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+public class Solution {
+ public int longestConsecutive(TreeNode root) {
+ return recursiveHelper(root, null, 0);
+ }
+
+ public int recursiveHelper(TreeNode curr, TreeNode parent, int depth) {
+ if (curr == null) {
+ return 0;
+ }
+ int currDepth = 0;
+ if (parent != null && parent.val + 1 == curr.val) {
+ currDepth = depth + 1;
+ } else {
+ currDepth = 1;
+ }
+ return Math.max(currDepth, Math.max(recursiveHelper(curr.left, curr, currDepth), recursiveHelper(curr.right, curr, currDepth)));
+ }
+}
+
+
+```
\ No newline at end of file
diff --git a/Java/Binary Tree Maximum Path Sum II.java b/Java/Binary Tree Maximum Path Sum II.java
old mode 100644
new mode 100755
index 0dbb7b8..89c790b
--- a/Java/Binary Tree Maximum Path Sum II.java
+++ b/Java/Binary Tree Maximum Path Sum II.java
@@ -1,7 +1,15 @@
-比Binary Tree Maximum Path Sum I 简单许多.
-因为条件给的更多:at least 1 node + have to start from root => have to have root.
-Single path: either left or right.
-If the path sum < 0, just skip it.
+M
+1526771382
+tags: Tree, DFS
+
+找到从max path sum from root. 条件: 至少有一个node.
+
+#### DFS
+- 比Binary Tree Maximum Path Sum I 简单许多. 因为条件给的更多:at least 1 node + have to start from root
+- root一定用到
+- 3种情况: curr node, curr+left, curr+right
+- 因为一定包括root, 说以从 `dfs(root, sum=0)` 开始, 每个level先加root, sum += root.val
+
```
/*
Binary Tree Maximum Path Sum II
@@ -22,6 +30,29 @@
Binary Tree
*/
+/*
+ 02.20.2016 recap
+ just return integer sum, so just traversal the entier binary tree via dfs
+ dfs: node, sum, return sum
+*/
+public class Solution {
+ public int maxPathSum2(TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+ return dfs(root, 0);
+ }
+ public int dfs (TreeNode node, int sum) {
+ if (node == null) {
+ return sum;
+ }
+ sum += node.val;
+ return Math.max(sum, Math.max(dfs(node.left, sum),
+ dfs(node.right, sum)));
+ }
+}
+
+
/*
Thoughts: maximum path sum from root, so it must include root, and it will be a single path
from root to some point in the tree.
@@ -29,17 +60,6 @@
'contains at least 1 node' -> at least have root.
However, depending on child is positive or negative, we choose add or no add child
*/
-/**
- * Definition of TreeNode:
- * public class TreeNode {
- * public int val;
- * public TreeNode left, right;
- * public TreeNode(int val) {
- * this.val = val;
- * this.left = this.right = null;
- * }
- * }
- */
public class Solution {
/**
* @param root the root of binary tree.
diff --git a/Java/Binary Tree Maximum Path Sum.java b/Java/Binary Tree Maximum Path Sum.java
old mode 100644
new mode 100755
index f3ad82e..2c0c798
--- a/Java/Binary Tree Maximum Path Sum.java
+++ b/Java/Binary Tree Maximum Path Sum.java
@@ -1,37 +1,71 @@
-有点难理解.
-复杂原因是:因为可能有负值啊。不能乱assume正数。
-single path max 的计算是为了给后面的comboMax用的。
-如果single path max小于0,那没有什么加到parent上面的意义,所以就被再次刷为0.
-combo的三种情况:(root可能小于0)1. 只有left, 2。 只有右边。 3. root大于0,那么就left,right,curr全部加起来。
- 情况1和情况2去一个最大值,
- 然后和情况三比较。
- 做了两个Math.max(). 然后就有了这一层的comboMax
-
-
-12.11.2015 recap:
- So totally, 5 conditions:
- (save in single:)
- left + curr.val
- right + curr.val
- (save in combo:)
- left,
- right,
- left + curr.val + right
+H
+1526524522
+tags: Tree, DFS, DP, Tree DP
+
+找max path sum, 可以从任意treeNode 到任意 treeNode.
+
+#### Kinda, Tree DP
+- 两个情况: 1. combo sum: left+right+root; 2. single path sum
+- Note1: the path needs to be continuous, curr node cannot be skipped
+- Note2: what about I want to skip curr node: handled by lower level of dfs(), where child branch max was compared.
+- Note3: skip left/right child branch sum, by comparing with 0. 小于0的, 没必要记录
+
+#### DP的思想
+- tree给我们2条branch, 每条branch就类似于 dp[i - 1], 这里类似于dp[left], dp[right] 这样
+- 找到 dp[left], dp[right] 以后, 跟 curr node结合.
+- 因为是找max sum, 并且可以skip nodes, 所以需要全局变量max
+- 每次dfs() return的一定是可以继续 `continuously link 的 path`, 所以return `one single path sum + curr value`.
+
+#### DFS, PathSum object
+- that just solves everything
+/*
+private class PathSum {
+ int singlePathMax;
+ int combinedPathMax;
+ PathSum(int singlePathMax, int combinedPathMax) {
+ this.singlePathMax = singlePathMax;
+ this.combinedPathMax = combinedPathMax;
+ }
+}
+*/
+
+#### Previous Notes
+##### Note1
+- 用 PathSum 比较特别. 没有 data structure的时候, 写起来比较繁琐.
+- 第一次做有点难理解,复杂原因是:因为可能有负值啊。不能乱assume正数。
+- single path max 的计算是为了给后面的comboMax用的。
+- 如果single path max小于0,那没有什么加到parent上面的意义,所以就被再次刷为0.
+- combo的三种情况:(root可能小于0)
+- 1. 只有left
+- 2. 只有right
+- 3. root大于0,那么就left,right,curr全部加起来。
+- 情况1和情况2取一个最大值,然后和情况三比较。做了两个Math.max(). 然后就有了这一层的comboMax
+
+##### Note2
+- 12.11.2015 recap
+- totally 5 conditions:
+- (save in single): left + curr.val OR right + curr.val
+- (save in combo):left, right, OR left + curr.val + right
+
```
/*
-23% Accepted
Given a binary tree, find the maximum path sum.
+
The path may start and end at any node in the tree.
+
+
Example
-Given the below binary tree,
- 1
- / \
- 2 3
-Return 6.
+Given the below binary tree:
+
+ 1
+ / \
+2 3
+return 6.
+
Tags Expand
-Dynamic Programming Tree Depth First Search
+Divide and Conquer Dynamic Programming Recursion
*/
@@ -46,7 +80,68 @@
* }
* }
*/
+// DP, DFS, 99.73%
+public class Solution {
+ int max = Integer.MIN_VALUE;
+
+ public int maxPathSum(TreeNode root) {
+ maxPathDown(root);
+ return max;
+ }
+
+ private int maxPathDown(TreeNode node) {
+ if (node == null) return 0;
+ int left = Math.max(0, maxPathDown(node.left)); // left single path
+ int right = Math.max(0, maxPathDown(node.right)); // right single path
+ max = Math.max(max, left + right + node.val); // compare combo max with global max
+ return Math.max(left, right) + node.val; // always return the max single continuous path
+ }
+}
+// Use a customized object to track single path, v.s. combo path
+public class Solution {
+ // Class used to carry sum in recursive dfs
+ private class PathSum {
+ int singlePathMax;
+ int combinedPathMax;
+ PathSum(int singlePathMax, int combinedPathMax) {
+ this.singlePathMax = singlePathMax;
+ this.combinedPathMax = combinedPathMax;
+ }
+ }
+
+ // Goal: find the combined path value, if applicable
+ public int maxPathSum(TreeNode root) {
+ PathSum result = dfs(root);
+ return result.combinedPathMax;
+ }
+
+ public PathSum dfs(TreeNode root) {
+ if (root == null) {
+ return new PathSum(0, Integer.MIN_VALUE);
+ }
+ //Divide
+ PathSum left = dfs(root.left);
+ PathSum right = dfs(root.right);
+
+ //Conquer
+
+ //Step 1: build single path max (continuous path sum including curr root)
+ int singlePathMax = Math.max(left.singlePathMax, right.singlePathMax) + root.val;
+ //If less than 0, set to 0. It'll be dropped for combinedPathMax, so leave it to 0.
+ singlePathMax = Math.max(singlePathMax, 0);
+
+ //Step2: build combined path max.
+ // Compare leftChild.combo vs. rightChild.combo
+ int combinedPathMax = Math.max(left.combinedPathMax, right.combinedPathMax);
+ // Compare with left.single + right.single + root.val
+ combinedPathMax = Math.max(combinedPathMax, left.singlePathMax + right.singlePathMax + root.val);
+
+ // Return the summary for the current node.
+ return new PathSum(singlePathMax, combinedPathMax);
+ }
+
+}
/*
@@ -95,8 +190,9 @@ public PathSumType helper(TreeNode root) {
int singlePathMax = Math.max(left.singlePathMax, right.singlePathMax) + root.val;
singlePathMax = Math.max(singlePathMax, 0);//If less than 0, no need to keep, because it only decrease parent-level max.
- //first comparison: does not include curr node at all(this would be applicable when curr.val < 0, so we take this condition into account)
+ //first comparison: does not include root node at all(this would be applicable when curr.val < 0, so we take this condition into account)
int combinedPathMax = Math.max(left.combinedPathMax, right.combinedPathMax);
+ //second comparison:
combinedPathMax = Math.max(combinedPathMax, left.singlePathMax + right.singlePathMax + root.val);
return new PathSumType(singlePathMax, combinedPathMax);
@@ -104,6 +200,4 @@ public PathSumType helper(TreeNode root) {
}
-
-
```
\ No newline at end of file
diff --git a/Java/Binary Tree Paths.java b/Java/Binary Tree Paths.java
old mode 100644
new mode 100755
index f2e8730..85e4d17
--- a/Java/Binary Tree Paths.java
+++ b/Java/Binary Tree Paths.java
@@ -1,7 +1,26 @@
-Recursive:分叉。Helper。
+E
+1519797926
+tags: Binary Tree, DFS, Backtracking
+
+给一个binary tree, 返回所有root-to-leaf path
+
+#### DFS, backtracking
+- Find all paths, bfs/dfs all works. dfs will be simplier to write
+- Recursive:分叉. dfs.
+- top->bottom: enumerate current node into the list, carry to next level, and backtrack
+- top->bottom is trivial to consider: path flows from top->bottom
+
+#### DFS, bottom->up
+- We can also take current node.left or node.right to generate list of results from the subproblem
+- let dfs return list of string candidates, and we can run pair the list with currenet node, once they come back.
+- TODO: can write code to practice
+
+#### Iterative
+- Iterative, 非递归练习了一下
+- 因为要每次切短list, 所以再加了一个Stack 来存level
+- 单这道题用dfs更简单, 因为找的就是从头到尾的path, 是dfs的pattern
+
-非递归练习了一下
-因为要每次切短list, 所以再加了一个Stack 来存level
```
/*
Binary Tree Paths
@@ -26,7 +45,82 @@
Binary Tree Binary Tree Traversal Facebook Google
*/
+// cleaner:
+class Solution {
+ public List binaryTreePaths(TreeNode root) {
+ List