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$1.class b/GenerateCodeTable$1.class
new file mode 100644
index 0000000..3f24036
Binary files /dev/null and b/GenerateCodeTable$1.class differ
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..91a6db3 100644
--- a/GenerateCodeTable.java
+++ b/GenerateCodeTable.java
@@ -1,113 +1,510 @@
-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.*;
+import java.util.stream.*;
+import java.text.SimpleDateFormat;
+
+/*
+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 String GIT_HUB_LINK = "https://github.com/awangdev/LintCode/blob/master/Java/";
+ private static String NOT_AVAILABLE = "N/A";
+ private static String LINTCODE_TOKEN = "[lint]";
+ private static String TOOL_TOKEN = "[tool]";
+ private static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+ /*
+ 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 timeComplexity;
+ private String spaceComplexity;
+ private String note;
+ private List tags;
+
+ public TableRow(
+ long date,
+ String fileName,
+ String level,
+ String tutorialLink,
+ String timeComplexity,
+ String spaceComplexity,
+ String note,
+ List tags) {
+ this.date = date;
+ this.fileName = fileName;
+ this.level = level;
+ this.timeComplexity = timeComplexity;
+ this.spaceComplexity = spaceComplexity;
+ this.tutorialLink = tutorialLink;
+ this.note = note;
+ this.tags = tags;
+ }
+
+ public String getLeetcodeNum() {
+ String[] fileNameArr = fileName.split("\\.");
+ if (LINTCODE_TOKEN.equals(fileNameArr[0].toLowerCase())) {
+ return LINTCODE_TOKEN;
+ }
+ if (TOOL_TOKEN.equals(fileNameArr[0].toLowerCase())) {
+ return TOOL_TOKEN;
+ }
+ try {
+ Integer.parseInt(fileNameArr[0]);
+ return fileNameArr[0];
+ } catch(Exception e) {
+ return NOT_AVAILABLE;
+ }
+ }
+
+ 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(int i) {
+ Date date = new Date(this.date);
+ return "|" + this.getLeetcodeNum() + "|[" + this.fileName + "](" + GIT_HUB_LINK + fileName.replace(" ", "%20")
+ + ")|" + this.level + "|" + this.tags + "|" + this.timeComplexity + "|" + this.spaceComplexity + "|Java|" + i + "|\n";
+ }
+ }
+
+ public static String TUTORIAL_KEY_WORD = "tutorial:";
+ public static String TAGS_KEY_WORD = "tags:";
+ public static String TIME_KEY_WORD = "time:";
+ public static String SPACE_KEY_WORD = "space:";
+ 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() + " | " +
+ "Java | " +
+ "
";
+ count++;
+ }
+ }
+
+ outputContent += "
";
+ return outputContent;
+ }
+
+
+ /*
+ Generate GitHub README contents
+ */
+ public String generateREADME(File[] listOfFiles) {
+ //Assemble output
+ String outputContent = "# Java Algorithm Problems\n\n" +
+ "| Leetcode# | Problem | Level | Tags | Time | Space | Language | Sequence |\n" +
+ "|:---------:|:------------|:------:|:----:|-----:|------:|:--------:|---------:|\n";
+ List tableRows = getTableRows(listOfFiles);
+ for (int i = 0; i < tableRows.size(); i++) {
+ outputContent += tableRows.get(i).getTableComposedLine(i);
+ }
+ return outputContent;
+ }
+
+ /* Generate the tags Table*/
+ public String generateTagREADME(File[] listOfFiles) {
+ String outputContent = generateTableOfContent("TagREADME.md") + "\n\n";
+ String header = "| Leetcode# | Problem | Level | Tags | Time | Space | Language | Sequence |\n" +
+ "|:---------:|:------------|:------:|:----:|-----:|------:|:--------:|---------:|\n";
+ List tableRows = getTableRows(listOfFiles);
+ Map> 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(entryTableRows.get(i).getTableComposedLine(i));
+ }
+ outputContent += sb.toString() + "\n\n\n";
+ }
+ return outputContent;
+ }
+
+ // Generate review files by tags
+ public String generateTagReviewPage(File[] listOfFiles) {
+ List tableRows = getTableRows(listOfFiles);
+ Map> 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) {
+ List tableRows = getTableRows(listOfFiles);
+ Map> 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";
+
+ 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("](" + GIT_HUB_LINK);
+ 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) {
+ List tableRows = new ArrayList<>();
+ for (File file : listOfFiles) {
+ if (file.getName().contains(".java")) {
+ tableRows.add(getTableRow(file.getName()));
+ }
+ }
+ List nonProcessedRows = tableRows.stream()
+ .filter(tableRow -> tableRow.getLeetcodeNum().equals(NOT_AVAILABLE))
+ .collect(Collectors.toList());
+ List processedLeetCodeRows = tableRows.stream()
+ .filter(tableRow -> !tableRow.getLeetcodeNum().equals(NOT_AVAILABLE)
+ && !tableRow.getLeetcodeNum().equals(LINTCODE_TOKEN) && !tableRow.getLeetcodeNum().equals(TOOL_TOKEN)
+ )
+ .collect(Collectors.toList());
+ List processedLintCodeRows = tableRows.stream()
+ .filter(tableRow -> tableRow.getLeetcodeNum().equals(LINTCODE_TOKEN))
+ .collect(Collectors.toList());
+ List processedToolCodeRows = tableRows.stream()
+ .filter(tableRow -> tableRow.getLeetcodeNum().equals(TOOL_TOKEN))
+ .collect(Collectors.toList());
+ Collections.sort(processedLeetCodeRows, Comparator.comparing(TableRow::getDate));
+ Collections.sort(processedLintCodeRows, Comparator.comparing(TableRow::getDate));
+ System.out.println("Non Reviewed Problems: " + nonProcessedRows.size()
+ + ", Reviewed LeetCode Problems: " + processedLeetCodeRows.size()
+ + ", Reviewed LintCode Problems: " + processedLintCodeRows.size());
+ List output = new ArrayList<>();
+ output.addAll(nonProcessedRows);
+ output.addAll(processedLintCodeRows);
+ output.addAll(processedToolCodeRows);
+ output.addAll(processedLeetCodeRows);
+ return output;
+ }
+
+ private TableRow getTableRow(String fileName) {
+ TableRow tableRow = null;
+ String tutorialLink = "";
+ String calculatedLevel = NOT_AVAILABLE;
+ String timeComplexity = "";
+ String spaceComplexity = "";
+ long timestamp = 0;
+ List tags = new ArrayList<>();
+
+ // get timestamp of file
+ File file = new File("Java/" + fileName);
+ timestamp = file.lastModified();
+
+ try {
+ 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();
+ }
+
+ // TODO: remove the legacy timestamp.
+ // Below are existing logic to parse timestamp. Remove when all timestamp is cleaned up.
+ if (line.length() != 0) {
+ try{
+ Long.parseLong(line);
+ line = reader.readLine().trim();
+ } catch(Exception e){ }
+ }
+
+ // 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);
+ line = reader.readLine().trim();
+ }
+
+ // Get Time
+ if (line.contains(TIME_KEY_WORD)) {
+ timeComplexity = line.substring(6).trim(); // "time:"
+ line = reader.readLine().trim();
+ }
+
+ // Get Space
+ if (line.contains(SPACE_KEY_WORD)) {
+ spaceComplexity = line.substring(7).trim(); // "space:"
+ }
+
+ // 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, timeComplexity, spaceComplexity, note, tags);
+ } catch (Exception e) {
+ System.err.format("IOException: %s%n. Filename: %s", e, fileName);
+ }
+ return tableRow;
+ }
+
+ private String calculateLevel(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 (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. Two Sum.java b/Java/1. Two Sum.java
new file mode 100755
index 0000000..a40872f
--- /dev/null
+++ b/Java/1. Two Sum.java
@@ -0,0 +1,141 @@
+E
+tags: Array, Hash Table
+time: O(n)
+space: O(n)
+
+#### HashMap
+- 相对暴力简洁: 找到一个value, 存一个index
+- 若在HashMap里面 match 到结果, 就return HashMap里存的index.
+- O(n) space && time.
+
+#### Sort array, two pointer
+- 前后++, --搜索. Sort 用时O(nlogn).
+- 1. 第一步 two pointer 找 value.
+- 2. 注意,要利用额外的空间保留original array, 用来时候找index. (此处不能用HashMap,因为以value 为key,但value可能重复)
+- O(n) space, O(nlogn) time.
+
+
+```
+/**
+LeetCode: 0-based answer
+Given an array of integers, return indices of the two numbers such that they add up to a specific target.
+
+You may assume that each input would have exactly one solution, and you may not use the same element twice.
+
+Example:
+
+Given nums = [2, 7, 11, 15], target = 9,
+
+Because nums[0] + nums[1] = 2 + 7 = 9,
+return [0, 1].
+*/
+/*
+Thoughts:
+ 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.
+ 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.
+*/
+class Solution {
+ public int[] twoSum(int[] nums, int target) {
+ int[] rst = new int[2];
+ if (nums == null || nums.length <= 1) return rst;
+
+ Map map = new HashMap<>();
+ for (int i = 0; i < nums.length; i++) {
+ if (map.containsKey(target - nums[i])) {
+ rst[0] = map.get(target - nums[i]);
+ rst[1] = i;
+ break;
+ }
+ map.put(nums[i], i);
+ }
+ return rst;
+ }
+}
+
+/*
+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.
+Example
+numbers=[2, 7, 11, 15], target=9
+return [1, 2]
+Note
+You may assume that each input would have exactly one solution
+Challenge
+Either of the following solutions are acceptable:
+O(n) Space, O(nlogn) Time
+O(n) Space, O(n) Time
+Tags Expand
+Two Pointers Sort Hash Table Array Airbnb Facebook
+*/
+
+//2. O(n) Space O(nlogn) time
+/*
+ Feels like binary search when looking at O(nlogn)
+ 1. sort
+ 2. loop all number
+ 3. binary search on rest
+*/
+public class Solution {
+ public int[] twoSum(int[] numbers, int target) {
+ if (numbers == null || numbers.length == 0) {
+ return null;
+ }
+ int[] original = new int[numbers.length];
+ for (int i = 0; i < numbers.length; i++) {
+ original[i] = numbers[i];
+ }
+
+ Arrays.sort(numbers);
+ int start = 0;
+ int end = numbers.length - 1;
+ int num1 = -1;
+ int num2 = -1;
+ while (start != end) {
+ int sum = numbers[start] + numbers[end];
+ if (sum == target) {
+ num1 = numbers[start];
+ num2 = numbers[end];
+ break;
+ }else if (sum < target) {
+ start++;
+ } else {
+ end--;
+ }
+ }
+
+ //Find the num1,num2 in original array and record the index
+ int[] rst = new int[2];
+ rst[0] = -1;
+ rst[1] = -1;
+ for (int i = 0; i < original.length; i++) {
+ if (original[i] == num1 || original[i] == num2) {
+ if (rst[0] == -1) {
+ rst[0] = i + 1;
+ } else {
+ rst[1] = i + 1;
+ break;
+ }
+ }
+ }
+ return rst;
+ }
+}
+
+
+
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/Java/10. Regular Expression Matching.java b/Java/10. Regular Expression Matching.java
new file mode 100755
index 0000000..40080e5
--- /dev/null
+++ b/Java/10. Regular Expression Matching.java
@@ -0,0 +1,187 @@
+H
+tags: String, DP, Sequence DP, Double Sequence DP, Backtracking
+
+跟WildCard Matching 一样, 分清楚情况讨论 string p last char is '*' 还有并不是 '*'
+
+IMPORTANT: '*' 需要有一个 prefix element [elm], so it becomes `[elm]*`. There 2 possible cases:
+- [elm] repeats 0 times: move p, j + 2
+- [elm] repeats 1 or more times: need s[i] == p[i], then move s, i+1
+
+#### DFS, Top-Down, Break into sub problems.
+- DFS on remaining of s and p. Analyze the different cases when next char == '*'
+- End case: both i,j reached end true; or one of them reached end.
+- The two different cases when given any index j on p, the p[j+1]=='*'
+ - TRUE:
+ - ignore p[j, j+1], continue from p[j+2]
+ - check if s[i]==p[j] or p[j]='.'; continue from s[i+1] and p
+ - FALSE: check i,j, and move forward with s[i+1], p[j+1]
+- If next p char != '*', check curr s[i] ?= p[i]
+- Improvement with memo with 2D Booelan[][] memo: much faster
+ - memo[i][j] records result the remaining strings: s.substring(i) compare with p.substring(j)
+ - use `Boolean`: when memo[i][j] != null, return something!
+
+#### DP, Sequence DP, Bottom-Up
+- Two sequence, DP, find if possible to match.
+- The '*' takes effect of preceding/prior element, so we can start matching from end.
+- DP[i][j]: is it possible to match s[0 ~ i - 1] and p[0 ~ j - 1].
+- Check last index of s and p, there can be a few possibilities:
+ - 1. s[i-1]==p[j-1] and they are normal characters => && dp[i - 1][j - 1];
+ - 2. p[j-1] == '.', match => dp[i - 1][j - 1]
+ - 3. p[j-1] == '*':
+ - a. ignore a* => |= dp[i][j - 2];
+ - b. use a* => |= dp[i - 1][j];
+- init: dp[0][j] and dp[i][0] will all be false since there cannot be any match.
+
+
+```
+/*
+Implement regular expression matching with support for '.' and '*'.
+
+'.' Matches any single character.
+'*' Matches zero or more of the preceding element.
+
+The matching should cover the entire input string (not partial).
+
+The function prototype should be:
+bool isMatch(const char *s, const char *p)
+
+Some examples:
+isMatch("aa","a") → false
+isMatch("aa","aa") → true
+isMatch("aaa","aa") → false
+isMatch("aa", "a*") → true
+isMatch("aa", ".*") → true
+isMatch("ab", ".*") → true
+isMatch("aab", "c*a*b") → true
+*/
+
+/*
+Method1:
+DFS on remaining of s and p. Analyze the different cases.
+End case: both i,j reached end true; or one of them reached end.
+
+The two different cases: given any index j on p, check if the j+1=='*'
+- YES:
+ - ignore p[j, j+1], continue from p[j+2]
+ - check if s[i]==p[j] or p[j]='.'; continue from s[i+1] and p
+- NO: check i,j, and move forward with s[i+1], p[j+1]
+*/
+
+class Solution {
+ int n, m;
+ public boolean isMatch(String s, String p) {
+ n = s.length();
+ m = p.length();
+
+ return dfs(s, 0, p, 0);
+ }
+
+ private boolean dfs(String s, int i, String p, int j) {
+ if (j >= m) return i >= n;
+
+ char pc = p.charAt(j);
+ if (j+1 < m && p.charAt(j + 1) == '*') {
+ if (dfs(s, i, p, j+2)) return true; // when * reuslts in 0, move j
+ if (i < n && (pc == '.' || s.charAt(i) == pc)) return dfs(s, i+1, p, j); // when * reuslts not as 0, move i
+ return false;
+ }
+ if (i < n && (pc == '.' || s.charAt(i) == pc)) { // next pc not equal to '*'
+ return dfs(s, i+1, p, j+1);
+ }
+ return false;
+ }
+}
+
+// DFS + Memoization
+class Solution {
+ int n, m;
+ Boolean[][] memo;
+ public boolean isMatch(String s, String p) {
+ n = s.length();
+ m = p.length();
+ memo = new Boolean[n+2][m+2];
+ return dfs(s, 0, p, 0);
+ }
+
+ private boolean dfs(String s, int i, String p, int j) {
+ if (j >= m) return i >= n;
+ if (memo[i][j] != null) return memo[i][j];
+
+ char pc = p.charAt(j);
+ if (j+1 < m && p.charAt(j + 1) == '*') {
+ // when * reuslts in 0 [elm], move j
+ memo[i][j+2] = dfs(s, i, p, j+2);
+ if (memo[i][j+2]) return true;
+
+ // when * reuslts not into 1 or more [elm], move i
+ if (i < n && (pc == '.' || s.charAt(i) == pc)) {
+ memo[i+1][j] = dfs(s, i+1, p, j);
+ return memo[i+1][j];
+ }
+ } else if (i < n && (pc == '.' || s.charAt(i) == pc)) { // next pc not equal to '*'
+ memo[i+1][j+1] = dfs(s, i+1, p, j+1);
+ return memo[i+1][j+1];
+ }
+ memo[i][j] = false;
+ return memo[i][j];
+ }
+}
+
+
+/*
+Method2: DP
+Thoughts:
+Two sequence, DP, find if possible to match.
+The '*' takes effect of preceding element, so we can start matching from end.
+DP[i][j]: is it possible to match s[0 ~ i - 1] and p[0 ~ j - 1].
+Check last index of s and p, there can be a few possibilities:
+1. s[i-1]==p[j-1] and they are normal characters => && dp[i - 1][j - 1];
+2. p[j-1] == '.', match => dp[i - 1][j - 1]
+3. p[j-1] == '*':
+ a. ignore a* => |= dp[i][j - 2];
+ b. use a* => |= dp[i - 1][j];
+
+init:
+dp[0][j] and dp[i][0] will all be false since there can't be any match.
+
+*/
+class Solution {
+ public boolean isMatch(String s, String p) {
+ if (s == null || p == null) return false;
+ int m = s.length(), n = p.length();
+ boolean[][] dp = new boolean[m + 1][n + 1];
+ char[] ss = s.toCharArray();
+ char[] pp = p.toCharArray();
+
+ for (int i = 0; i <= m; i++) {
+ for (int j = 0; j <= n; j++) {
+ if (i == 0 && j == 0) {
+ dp[i][j] = true;
+ continue;
+ }
+ if (j == 0) { // When p is empty but s is not empty, should not match
+ dp[i][j] = false;
+ continue;
+ }
+
+ // j >= 1
+ dp[i][j] = false;
+ if (pp[j - 1] != '*') {
+ if (i >= 1 && (ss[i - 1] == pp[j - 1] || pp[j - 1] == '.')) {
+ dp[i][j] = dp[i - 1][j - 1];
+ }
+ } else { // tail = '*'. ex: a*
+ if (j >= 2 ) { // ignore a*, repeat 0 times
+ dp[i][j] |= dp[i][j - 2];
+ }
+ // repeat the char befeore * for 1 time, so ss[i-1] should match pp[j-2] or pp[j-2] == '.'
+ if (j >= 2 && i >= 1 && (ss[i - 1] == pp[j - 2] || pp[j - 2] == '.')) {
+ dp[i][j] |= dp[i - 1][j];
+ }
+ }
+ }
+ }
+ return dp[m][n];
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/100. Same Tree.java b/Java/100. Same Tree.java
new file mode 100755
index 0000000..cc8c42a
--- /dev/null
+++ b/Java/100. Same Tree.java
@@ -0,0 +1,100 @@
+E
+tags: Tree, DFS, BFS
+time: O(n)
+space: O(logn)
+
+给两个 binary tree, 看两个tree是否identical.
+
+#### Method1: DFS
+- DFS. 确定leaf条件, && with all dfs(sub1, sub2).
+- 这里无论如何都要走过所有的node, 所以dfs更加合适, 好写.
+
+#### Method2: BFS with 2 queues
+- 两个queue存每个tree的所有current level node. Check equality, check queue size.
+- Populate next level by nodes at current level.
+
+```
+/*
+Given two binary trees, write a function to check if they are the same or not.
+
+Two binary trees are considered the same if they are structurally identical
+and the nodes have the same value.
+
+
+Example 1:
+
+Input: 1 1
+ / \ / \
+ 2 3 2 3
+
+ [1,2,3], [1,2,3]
+
+Output: true
+Example 2:
+
+Input: 1 1
+ / \
+ 2 2
+
+ [1,2], [1,null,2]
+
+Output: false
+Example 3:
+
+Input: 1 1
+ / \ / \
+ 2 1 1 2
+
+ [1,2,1], [1,1,2]
+
+Output: false
+*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+/*
+Method1: DFS
+Use the function itself with dfs.
+Check p == q, p.left==q.left, p.right==q.right
+*/
+class Solution {
+ public boolean isSameTree(TreeNode p, TreeNode q) {
+ if (p == null || q == null) return p == null && q == null;
+ return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
+ }
+}
+
+// Method2: BFS
+class Solution {
+ public boolean isSameTree(TreeNode p, TreeNode q) {
+ Queue pp = new LinkedList<>();
+ Queue qq = new LinkedList<>();
+ pp.offer(p);
+ qq.offer(q);
+
+ while (!pp.isEmpty() && !qq.isEmpty()) {
+ p = pp.poll();
+ q = qq.poll();
+ if (p == null && q == null) continue;
+ if (p == null ^ q == null) return false;
+ if (p.val != q.val) return false;
+ offer(p, pp);
+ offer(q, qq);
+ }
+
+ return true;
+ }
+
+ private void offer(TreeNode node, Queue queue) {
+ queue.offer(node.left);
+ queue.offer(node.right);
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1004. Max Consecutive Ones III.java b/Java/1004. Max Consecutive Ones III.java
new file mode 100755
index 0000000..5c8c823
--- /dev/null
+++ b/Java/1004. Max Consecutive Ones III.java
@@ -0,0 +1,80 @@
+M
+tags: Sliding Window, Two Pointers
+time: O(n)
+space: O(1)
+
+
+#### Sliding window + Left/Right Two Pointers
+- https://leetcode.com/problems/max-consecutive-ones-iii/solution/
+- Start with DFS thought, but realize redundant calculations:
+ - we never need to flip 2 indexes [A], [C] from 0 -> 1, if there is a [B] in middle that is 0 too
+ - the flipped k zeroes must be consecutive too
+- we can utilize two pointers to establish a window that captures k zeroes
+ - always expend right pointer; if seeing an zero, k--
+ - note: `len = right - left + 1` is the ongoing max length
+ - when k < 0 (too many zeros), we need to slide the left side of the window to make sure:
+ - keep window len
+ - potentially do k++ when A[left]==0
+- goal: matain a max size of the window, until right == n
+- return (right - left). at this moment, right == n, so no need to (right - left + 1)
+
+```
+
+/*
+Given an array A of 0s and 1s, we may change up to K values from 0 to 1.
+
+Return the length of the longest (contiguous) subarray that contains only 1s.
+
+
+
+Example 1:
+
+Input: A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
+Output: 6
+Explanation:
+[1,1,1,0,0,1,1,1,1,1,1]
+Bolded numbers were flipped from 0 to 1. The longest subarray is underlined.
+Example 2:
+
+Input: A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
+Output: 10
+Explanation:
+[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
+Bolded numbers were flipped from 0 to 1. The longest subarray is underlined.
+
+
+Note:
+
+1 <= A.length <= 20000
+0 <= K <= A.length
+A[i] is 0 or 1
+*/
+/*
+- Start with DFS thought, but realize redundant calculations:
+ - we never need to flip 2 indexes [A], [C] from 0 -> 1, if there is a [B] in middle that is 0 too
+ - the flipped k zeroes must be consecutive too
+- we can utilize two pointers to establish a window that captures k zeroes
+ - always expend right pointer; if seeing an zero, k--
+ - note: `len = right - left + 1` is the ongoing max length
+ - when k < 0 (too many zeros), we need to slide the left side of the window to make sure:
+ - keep window len
+ - potentially do k++ when A[left]==0
+- goal: matain a max size of the window, until right == n
+- return (right - left). at this moment, right == n, so no need to (right - left + 1)
+*/
+class Solution {
+
+ public int longestOnes(int[] A, int k) {
+ int left = 0, right = 0, n = A.length;
+ while (right < n) {
+ if (A[right++] == 0) k--;
+ if (k < 0) {
+ if (A[left] == 0) k++;
+ left++;
+ }
+ }
+ return right - left; // at the end, right == n
+ }
+
+}
+```
\ No newline at end of file
diff --git a/Java/1007. Minimum Domino Rotations For Equal Row.java b/Java/1007. Minimum Domino Rotations For Equal Row.java
new file mode 100755
index 0000000..b5baf80
--- /dev/null
+++ b/Java/1007. Minimum Domino Rotations For Equal Row.java
@@ -0,0 +1,164 @@
+M
+tags: Array, Greedy
+time: O(n)
+space: O(1)
+
+
+#### Method1: Count all occurrance, and count on overlap indexes
+- when there is a value that can cover entire row of size n
+ - it must be: `n = countA[i] + countB[i] - overlap[i]`
+- Code easy to write and read
+- time: O(n)
+- space: O(1)
+
+#### Method2: Negative count
+- Observation: if A[0] works, no need to check B[0].
+- Because if both A[0] and B[0] exist in all dominoes,
+ - when you swap A[0] in a whole row,
+ - you will swap B[0] in a whole at the same time.
+ - The result of trying A[0] and B[0] will be the same.
+- time: O(n)
+- space: O(1)
+
+#### Method3: positive count Match
+- there should exist 1 numbers, that can appear in (A[i], B[i]).
+- failure case: there exist at least 1 index, that does not have the common number
+- maximum case: there can be 2 numbers, that both will make it work.
+- findCommon2, and count them:
+ - set.add(A[0], A[B]),
+ - if any new one does not exist in set, remove it from set
+ - if set is empty() , return -1
+- use the 2 numbers from set to do a sweep and count in A, O(n), return the less appearance one.
+- time: O(n)
+- space: O(1)
+
+```
+
+/**
+In a row of dominoes, A[i] and B[i] represent the top and bottom halves of the i-th domino. (A domino is a tile with two numbers from 1 to 6 - one on each half of the tile.)
+
+We may rotate the i-th domino, so that A[i] and B[i] swap values.
+
+Return the minimum number of rotations so that all the values in A are the same, or all the values in B are the same.
+
+If it cannot be done, return -1.
+
+
+Example 1:
+
+
+
+Input: A = [2,1,2,4,2,2], B = [5,2,6,2,3,2]
+Output: 2
+Explanation:
+The first figure represents the dominoes as given by A and B: before we do any rotations.
+If we rotate the second and fourth dominoes, we can make every value in the top row equal to 2, as indicated by the second figure.
+Example 2:
+
+Input: A = [3,5,1,2,3], B = [3,6,3,3,4]
+Output: -1
+Explanation:
+In this case, it is not possible to rotate the dominoes to make one row of values equal.
+
+
+Note:
+
+1 <= A[i], B[i] <= 6
+2 <= A.length == B.length <= 20000
+*/
+
+/*
+#### Method1: Count all occurrance, and count on overlap indexes
+ - when there is a value that can cover entire row of size n
+ - it must be: n = countA[i] + countB[i] - overlap[i].
+ - return a min flip count
+- time: O(n)
+- space: O(1)
+*/
+class Solution {
+ public int minDominoRotations(int[] A, int[] B) {
+ int[] countA = new int[7], countB = new int[7], overlap = new int[7];
+ int n = A.length;
+ for (int i = 0; i < n; ++i) {
+ countA[A[i]]++;
+ countB[B[i]]++;
+ if (A[i] == B[i]) overlap[A[i]]++;
+ }
+ for (int i = 1; i < 7; ++i) {
+ if (countA[i] + countB[i] - overlap[i] == n) return n - Math.max(countA[i], countB[i]);
+ }
+ return -1;
+ }
+}
+
+/*
+#### Method2: Negative count
+- Observation: if A[0] works, no need to check B[0].
+ - Because if both A[0] and B[0] exist in all dominoes,
+ - when you swap A[0] in a whole row,
+ - you will swap B[0] in a whole at the same time.
+ - The result of trying A[0] and B[0] will be the same.
+- time: O(n)
+- space: O(1)
+*/
+class Solution {
+ public int minDominoRotations(int[] A, int[] B) {
+ if (A == null || B == null || A.length == 0 || B.length == 0) return 0;
+
+ int rotationWithA = checkRotation(A, B, A[0]);
+ if (rotationWithA != -1 || A[0] == B[0]) return rotationWithA;
+ return checkRotation(A, B, B[0]); // if trial with A[0], try B[0]
+ }
+
+ private int checkRotation(int[] A, int[] B, int candidate) {
+ int rotationA = 0, rotationB = 0;
+ for (int i = 0; i < A.length; i++) {
+ if (A[i] != candidate && B[i] != candidate) return -1;
+ else if (A[i] != candidate) rotationA++; // flip A to set to correct candidate
+ else if (B[i] != candidate) rotationB++;
+ }
+ return Math.min(rotationA, rotationB);
+ }
+}
+
+
+/*
+#### Method3: positive count Match
+- there should exist 1 numbers, that can appear in (A[i], B[i]).
+- failure case: there exist at least 1 index, that does not have the common number
+- maximum case: there can be 2 numbers, that both will make it work.
+- findCommon2, and count them:
+ - set.add(A[0], A[B]),
+ - if any new one does not exist in set, remove it from set
+ - if set is empty() , return -1
+- use the 2 numbers from set to do a sweep and count in A, O(n), return the less appearance one.
+- time: O(n)
+- space: O(1)
+*/
+class Solution {
+ public int minDominoRotations(int[] A, int[] B) {
+ if (A == null || B == null || A.length == 0 || B.length == 0) return 0;
+ int n = A.length;
+ // validation
+ Integer a = A[0], b = B[0];
+ for (int i = 1; i < n; i++) {
+ if (a != null && a != A[i] && a != B[i]) a = null;
+ if (b != null && b != A[i] && b != B[i]) b = null;
+ if (a == null && b == null) return -1;
+ }
+
+ if (a == null) return n - Math.max(count(B, b), count(A, b));
+ if (b == null) return n - Math.max(count(B, a), count(A, a));
+ int countA = n - Math.max(count(A, a), count(A, b));
+ int countB = n - Math.max(count(B, a), count(B, b));
+ return Math.min(countA, countB);
+ }
+
+ private int count(int[] A, Integer candidate) {
+ int count = 0;
+ for (int num : A) count += (candidate == num) ? 1 : 0;
+ return count;
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/1008. Construct Binary Search Tree from Preorder Traversal.java b/Java/1008. Construct Binary Search Tree from Preorder Traversal.java
new file mode 100755
index 0000000..c35f86f
--- /dev/null
+++ b/Java/1008. Construct Binary Search Tree from Preorder Traversal.java
@@ -0,0 +1,76 @@
+M
+tags: DFS, Tree
+time: O(n)
+space: O(n)
+
+#### Method1: Top Down DFS
+- This approach highly relies on the preorder rules
+ - we can use validation rules to navigate throug hteh preorder array
+ - use a global index
+- time: O(n)
+
+
+```
+/**
+Return the root node of a binary search tree that matches the given preorder traversal.
+
+(Recall that a binary search tree is a binary tree where for every node, any descendant of node.left has a value < node.val, and any descendant of node.right has a value > node.val. Also recall that a preorder traversal displays the value of the node first, then traverses node.left, then traverses node.right.)
+
+
+
+Example 1:
+
+Input: [8,5,1,7,10,12]
+Output: [8,5,10,1,7,null,12]
+
+
+
+Note:
+
+1 <= preorder.length <= 100
+The values of preorder are distinct.
+*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+/*
+Method1: Top Down O(n)
+- Use preorder to pick one index at a time
+*/
+class Solution {
+ int index = 0;
+ public TreeNode bstFromPreorder(int[] preorder) {
+ if (preorder == null || preorder.length == 0) return null;
+
+ return dfs(preorder, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ }
+
+ private TreeNode dfs(int[] preorder, int min, int max) {
+ if (index == preorder.length) return null;
+ int val = preorder[index];
+
+ if (val <= min || val >= max) return null;
+ index++;
+ TreeNode node = new TreeNode(val);
+ node.left = dfs(preorder, min, val);
+ node.right = dfs(preorder, val, max);
+ return node;
+ }
+}
+
+/*
+Alternatives tried: use start as root; in remaining array, search for mid point such that
+- nums[mid] < root.val < nums[mid + 1]
+- we can split the array into 2 parts and build sub tree accordingly
+- time: O(n * logn) since it requires search. Not prefered
+
+*/
+
+```
\ No newline at end of file
diff --git a/Java/101. Symmetric Tree.java b/Java/101. Symmetric Tree.java
new file mode 100755
index 0000000..e7a8ff7
--- /dev/null
+++ b/Java/101. Symmetric Tree.java
@@ -0,0 +1,151 @@
+E
+tags: Tree, DFS, BFS
+time: O(n)
+space: O(n)
+
+检查tree是否symmetric
+
+注意Symmetric Binary Tree的例子和定义: 是镜面一样的对称. 并不是说左右两个sub-tree相等。
+
+#### Method1: DFS
+- Recursively check symmetrically相对应的Node.
+- 每个node的children都和镜面另外一边相对的node的children刚好成镜面反射位置。
+
+#### Method2: interative with queue
+- put left or right children in pair
+
+#### Method3: iterative with Stack
+- stack1: 左手边sub-tree先加left, 再加right child;
+- stack2: 右手边sub-tree先加right child, 再加left child。
+- process时,若symmetric,所有stack里面出来的node会一一对应。
+
+```
+/*
+Given a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).
+
+Example
+ 1
+ / \
+ 2 2
+ / \ / \
+3 4 4 3
+is a symmetric binary tree.
+
+ 1
+ / \
+ 2 2
+ \ \
+ 3 3
+is not a symmetric binary tree.
+
+Challenge
+Can you solve it both recursively and iteratively?
+
+Tags Expand
+Binary Tree
+*/
+
+/*
+ Thoughts:
+ verify that left and right tree are identical
+ A.val == B.val
+ check(A.left, B.left)
+ check(A.right, B.right)
+*/
+/**
+ * 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;
+ * }
+ * }
+ */
+
+class Solution {
+ public boolean isSymmetric(TreeNode root) {
+ if (root == null) return true;
+ return dfs(root.left, root.right);
+ }
+
+ private boolean dfs(TreeNode left, TreeNode right) {
+ if (left == null && right == null) return true;
+ if (left == null || right == null) return false;
+ return left.val == right.val
+ && dfs(left.right, right.left)
+ && dfs(left.left, right.right);
+ }
+}
+
+//Non-recursive, iterative
+
+class Solution {
+ public boolean isSymmetric(TreeNode root) {
+ if (root == null) return true;
+ Queue queue = new LinkedList<>();
+ queue.offer(root.left);
+ queue.offer(root.right);
+
+ while (!queue.isEmpty()) {
+ TreeNode left = queue.poll();
+ TreeNode right = queue.poll();
+
+ if (left == null && right == null) continue;
+ if (left == null || right == null) return false;
+ if (left.val != right.val) return false;
+ queue.offer(left.left);
+ queue.offer(right.right);
+ queue.offer(left.right);
+ queue.offer(right.left);
+ }
+
+ return true;
+ }
+}
+
+/*
+ Thoughts:
+ Use 2 stack to hold the child that's needed to compare.
+ Have to use stack, otherwise, can't iterate through root node.
+*/
+
+public class Solution {
+ public boolean isSymmetric(TreeNode root) {
+ if (root == null) {
+ return true;
+ }
+
+ Stack s1 = new Stack();
+ Stack s2 = new Stack();
+ s1.push(root.left);
+ s2.push(root.right);
+ while (!s1.isEmpty() && !s2.isEmpty()) {
+ TreeNode node1 = s1.pop();
+ TreeNode node2 = s2.pop();
+ if (node1 == null && node2 == null) {
+ continue;
+ } else if (node1 == null || node2 == null) {
+ return false;
+ } else if (node1.val != node2.val) {
+ return false;
+ }
+ s1.push(node1.left);
+ s2.push(node2.right);
+ s1.push(node1.right);
+ s2.push(node2.left);
+ }
+
+ return true;
+ }
+}
+
+
+
+
+
+
+
+
+```
diff --git a/Java/102. Binary Tree Level Order Traversal.java b/Java/102. Binary Tree Level Order Traversal.java
new file mode 100755
index 0000000..19cdbe1
--- /dev/null
+++ b/Java/102. Binary Tree Level Order Traversal.java
@@ -0,0 +1,106 @@
+M
+tags: Tree, BFS, DFS
+time: O(n)
+space: O(n)
+
+如题.
+
+#### Method1: BFS
+- 最普通,Non-recursive: BFS, queue, 用个queue.size()来end for loop:换行。
+- 或者用两个queue. 当常规queue empty,把backup queue贴上去
+
+#### Method2: DFS
+- 每个level都应该有个ArrayList. 那么用一个int level来查看:是否每一层都有了相应的ArrayList。
+- 如果没有,就加上一层。
+- 之后每次都通过DFS在相应的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},
+
+ 3
+ / \
+ 9 20
+ / \
+ 15 7
+
+
+return its level order traversal as:
+
+[
+ [3],
+ [9,20],
+ [15,7]
+]
+Challenge
+Challenge 1: Using only 1 queue to implement it.
+
+Challenge 2: Use DFS algorithm to do it.
+
+Tags Expand
+Queue Binary Tree Breadth First Search Binary Tree Traversal Uber LinkedIn Facebook
+
+*/
+
+/**
+ * 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 {
+ 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) {
+ 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;
+ }
+}
+
+//Method2: DFS
+//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 List> levelOrder(TreeNode root) {
+ List> result = new ArrayList<>();
+ if (root == null) return result;
+
+ dfs(root, 0, result);
+ return result;
+ }
+
+ public void dfs(TreeNode root, int level, List> rst) {
+ if (root == null) return;
+ if (level >= rst.size()) rst.add(new ArrayList<>());
+ rst.get(level).add(root.val);
+ dfs(root.left, level + 1, rst);
+ dfs(root.right, level + 1, rst);
+ }
+}
+
+
+```
\ No newline at end of file
diff --git a/Java/1021. Remove Outermost Parentheses.java b/Java/1021. Remove Outermost Parentheses.java
new file mode 100755
index 0000000..657ce43
--- /dev/null
+++ b/Java/1021. Remove Outermost Parentheses.java
@@ -0,0 +1,99 @@
+E
+tags: Stack
+
+#### Stack
+- use stack to hold potential pair
+- when stack is empty: detect outtermost element, dont add to final result
+- time: O(n), space O(n)
+
+#### Count occurance
+- solution from discussion, time O(n), space O(1)
+- save space, but less scalable: think about if there are 100 different pairs, then the couting will be a bit complex to handle.
+
+```
+/*
+A valid parentheses string is either empty (""), "(" + A + ")", or A + B, where A and B are valid parentheses strings, and + represents string concatenation. For example, "", "()", "(())()", and "(()(()))" are all valid parentheses strings.
+
+A valid parentheses string S is primitive if it is nonempty, and there does not exist a way to split it into S = A+B, with A and B nonempty valid parentheses strings.
+
+Given a valid parentheses string S, consider its primitive decomposition: S = P_1 + P_2 + ... + P_k, where P_i are primitive valid parentheses strings.
+
+Return S after removing the outermost parentheses of every primitive string in the primitive decomposition of S.
+
+
+
+Example 1:
+
+Input: "(()())(())"
+Output: "()()()"
+Explanation:
+The input string is "(()())(())", with primitive decomposition "(()())" + "(())".
+After removing outer parentheses of each part, this is "()()" + "()" = "()()()".
+Example 2:
+
+Input: "(()())(())(()(()))"
+Output: "()()()()(())"
+Explanation:
+The input string is "(()())(())(()(()))", with primitive decomposition "(()())" + "(())" + "(()(()))".
+After removing outer parentheses of each part, this is "()()" + "()" + "()(())" = "()()()()(())".
+Example 3:
+
+Input: "()()"
+Output: ""
+Explanation:
+The input string is "()()", with primitive decomposition "()" + "()".
+After removing outer parentheses of each part, this is "" + "" = "".
+
+
+Note:
+
+S.length <= 10000
+S[i] is "(" or ")"
+S is a valid parentheses string
+
+ */
+
+class Solution {
+ public String removeOuterParentheses(String S) {
+ if (S == null || S.length() == 0) return S;
+
+ Stack stack = new Stack<>();
+ StringBuffer sb = new StringBuffer();
+
+ for (char c : S.toCharArray()) {
+ if (stack.isEmpty()) { // detect outter most element
+ stack.push(c);
+ } else {
+ if (isPair(stack.peek(), c)) { // handle pair
+ stack.pop();
+ if (!stack.isEmpty()) {
+ sb.append(c);
+ }
+ } else {// handle single
+ stack.push(c);
+ sb.append(c);
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private boolean isPair(char a, char b) {
+ return a == '(' && b ==')';
+ }
+}
+
+// count
+class Solution {
+ public String removeOuterParentheses(String S) {
+ StringBuilder s = new StringBuilder();
+ int count = 0;
+ for (char c : S.toCharArray()) {
+ if (c == '(' && count++ > 0) s.append(c);
+ if (c == ')' && count-- > 1) s.append(c);
+ }
+ return s.toString();
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1026. Maximum Difference Between Node and Ancestor.java b/Java/1026. Maximum Difference Between Node and Ancestor.java
new file mode 100755
index 0000000..4f814f2
--- /dev/null
+++ b/Java/1026. Maximum Difference Between Node and Ancestor.java
@@ -0,0 +1,99 @@
+M
+tags: Tree, DFS
+time: O(n)
+space: O(logn)
+
+#### Method1: Top-Down DFS
+- cache parent max and min => produce current max and min
+- pass the max and min to dfs
+- compare and return the max of dfs(left), dfs(right)
+- time: O(n)
+- space: O(logn)
+- easy to write, a bit hard to think of
+
+#### Method2: Bottom-up DFS
+- pass up the local (min, max) as object `Val{max, min}`
+- easy to think of, but more code to write
+
+```
+/*
+
+Given the root of a binary tree, find the maximum value V for which there exists different nodes A and B where V = |A.val - B.val| and A is an ancestor of B.
+
+(A node A is an ancestor of B if either: any child of A is equal to B, or any child of A is an ancestor of B.)
+
+
+
+Example 1:
+
+
+
+Input: [8,3,10,1,6,null,14,null,null,4,7,13]
+Output: 7
+Explanation:
+We have various ancestor-node differences, some of which are given below :
+|8 - 3| = 5
+|3 - 7| = 4
+|8 - 1| = 7
+|10 - 13| = 3
+Among all possible differences, the maximum value of 7 is obtained by |8 - 1| = 7.
+
+
+Note:
+
+The number of nodes in the tree is between 2 and 5000.
+Each node will have value between 0 and 100000.
+
+*/
+// Method1
+class Solution {
+ public int maxAncestorDiff(TreeNode root) {
+ return dfs(root, root.val, root.val);
+ }
+
+ private int dfs(TreeNode node, int max, int min) {
+ if (node == null) return max - min;
+ max = Math.max(max, node.val);
+ min = Math.min(min, node.val);
+ return Math.max(dfs(node.left, max, min), dfs(node.right, max, min));
+ }
+}
+
+
+/*
+
+Method2: bottom up approach: pass up the local (min, max)
+- end state: leaf
+-
+*/
+class Solution {
+
+ class Val{
+ int max, min;
+ public Val(int max, int min) {
+ this.max = max;
+ this.min = min;
+ }
+ }
+
+ int rst = Integer.MIN_VALUE;
+
+ public int maxAncestorDiff(TreeNode root) {
+ dfs(root);
+ return rst;
+ }
+
+ private Val dfs(TreeNode node) {
+ if (node == null) return new Val(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ if (node.left == null && node.right == null) return new Val(node.val, node.val);
+ Val left = dfs(node.left), right = dfs(node.right);
+ int min = Math.min(left.min, right.min);
+ int max = Math.max(left.max, right.max);
+
+ int maxDiff = Math.max(Math.abs(node.val - min), Math.abs(node.val - max));
+ rst = Math.max(rst, maxDiff);
+
+ return new Val(Math.max(node.val, max), Math.min(node.val, min));
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/103. Binary Tree Zigzag Level Order Traversal.java b/Java/103. Binary Tree Zigzag Level Order Traversal.java
new file mode 100755
index 0000000..3c71b4f
--- /dev/null
+++ b/Java/103. Binary Tree Zigzag Level Order Traversal.java
@@ -0,0 +1,78 @@
+M
+tags: Stack, Tree, BFS
+time: O(n)
+space: O(n)
+
+#### Queue
+- 简单的level traversal.根据level奇数偶数而add到不同位子.
+- Option1: based on level % 2, insert to front/end of list
+- Option2: based on level, insert right/left of node into queue
+
+```
+/*
+Given a binary tree, return the zigzag level order traversal of its nodes' values.
+(ie, from left to right, then right to left for the next level and alternate between).
+
+Example
+Given binary tree {3,9,20,#,#,15,7},
+
+ 3
+ / \
+ 9 20
+ / \
+ 15 7
+
+
+return its zigzag level order traversal as:
+
+[
+ [3],
+ [20,9],
+ [15,7]
+]
+Tags Expand
+Tree Search Breadth First Search Queue Binary Tree
+
+*/
+
+/**
+ * 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;
+ * }
+ * }
+ */
+
+//BFS. first level = 0; level % 2 = 1, list.add(0, ...)
+public class Solution {
+ public List> zigzagLevelOrder(TreeNode root) {
+ List> rst = new ArrayList<>();
+ if (root == null) return rst;
+
+ int level = 0, size = 0;
+ Queue queue = new LinkedList<>();
+ queue.offer(root);
+
+ while (!queue.isEmpty()) {
+ size = queue.size();
+ List list = new ArrayList<>();
+ for (int i = 0 ; i < size; i++) {
+ TreeNode node = queue.poll();
+ if (level % 2 == 0) list.add(node.val);
+ else list.add(0, node.val);
+ if(node.left!= null) queue.offer(node.left);
+ if(node.right!= null) queue.offer(node.right);
+ }
+ level++;
+ rst.add(list);
+ }
+
+ return rst;
+ }
+}
+
+```
diff --git a/Java/1033. Moving Stones Until Consecutive.java b/Java/1033. Moving Stones Until Consecutive.java
new file mode 100755
index 0000000..1e6f393
--- /dev/null
+++ b/Java/1033. Moving Stones Until Consecutive.java
@@ -0,0 +1,102 @@
+E
+tags: Sort, Basic Implementation
+time: O(1), only 3 elements
+space: O(1)
+
+#### Analyze to understand
+- put 3 elements into array, sort and follow below rules:
+- min:
+ - if 3 elements consecutive, 0 move.
+ - if only 1 pair of the two elemnets consecutive or if they have 1 slot in between, it needs exactly 1 move
+ - otherwise, at most 2 moves
+- max: # of open slots between them (high - low + 1) - n, where n = 3
+- Follow up: `1040. Moving Stones Until Consecutive` is more interesting with special rulese (cannot move to `ending spot`), and it uses sliding window concept
+
+```
+/*
+Three stones are on a number line at positions a, b, and c.
+
+Each turn, you pick up a stone at an endpoint (ie., either the lowest or highest position stone), and move it to an unoccupied position between those endpoints. Formally, let's say the stones are currently at positions x, y, z with x < y < z. You pick up the stone at either position x or position z, and move that stone to an integer position k, with x < k < z and k != y.
+
+The game ends when you cannot make any more moves, ie. the stones are in consecutive positions.
+
+When the game ends, what is the minimum and maximum number of moves that you could have made? Return the answer as an length 2 array: answer = [minimum_moves, maximum_moves]
+
+
+
+Example 1:
+
+Input: a = 1, b = 2, c = 5
+Output: [1,2]
+Explanation: Move the stone from 5 to 3, or move the stone from 5 to 4 to 3.
+Example 2:
+
+Input: a = 4, b = 3, c = 2
+Output: [0,0]
+Explanation: We cannot make any moves.
+Example 3:
+
+Input: a = 3, b = 5, c = 1
+Output: [1,2]
+Explanation: Move the stone from 1 to 4; or move the stone from 1 to 2 to 4.
+
+
+Note:
+
+1 <= a <= 100
+1 <= b <= 100
+1 <= c <= 100
+a != b, b != c, c != a
+
+ */
+
+/*
+- min: min dist between them or 2
+- max: # of open slots between them c - a + 1 - 3
+*/
+class Solution {
+ public int[] numMovesStones(int a, int b, int c) {
+ int[] arr = new int[]{a, b, c};
+ Arrays.sort(arr);
+ int max = arr[2] - arr[0] - 2;
+ if (arr[2] - arr[0] == 2) return new int[]{0, max};
+ if (arr[1] - arr[0] <= 2 || arr[2] - arr[1] <= 2) return new int[]{1, max};
+ return new int[]{2, max};
+ }
+}
+
+/*
+if consecutive pts, no need to move, return {0, 0}
+max steps: the amount of empty slots between end - start - 2
+min steps case1:
+if min of the two intervals has <= 1 spot, we can fill the spot => 1 step
+if min of the two intervals has > 1 spot, we have to move 2 steps.
+
+Tip:
+Sort input, no need manual find min/mid/max. Adds some delay.
+*/
+class Solution {
+ public int[] numMovesStones(int a, int b, int c) {
+ int[] input = {a, b, c};
+ Arrays.sort(input);
+
+ // calculate
+ int max = calDist(input[0], input[2]) - 1;
+ int left = calDist(input[0], input[1]);
+ int right = calDist(input[1], input[2]);
+
+ int min = 2;
+ if (left + right == 0) {
+ min = 0;
+ } else if (Math.min(left, right) <= 1) {
+ min = 1;
+ }
+
+ return new int[] {min, max};
+ }
+
+ private int calDist(int start, int end) {
+ return end - start - 1;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/104. Maximum Depth of Binary Tree.java b/Java/104. Maximum Depth of Binary Tree.java
new file mode 100755
index 0000000..98a7b5c
--- /dev/null
+++ b/Java/104. Maximum Depth of Binary Tree.java
@@ -0,0 +1,61 @@
+E
+tags: DFS, Tree
+
+给一个binary tree, 找最深depth
+
+#### DFS
+- 这里要走过所有的node, 所以dfs非常合适
+- Divide and conquer.
+- 维持一个最大值: Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
+- 注意check root == null
+
+#### Note
+- BFS is doable as well, but a bit more code to write: tracks largest level we reach
+
+```
+/*
+Given a binary tree, find its maximum depth.
+
+The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
+
+Note: A leaf is a node with no children.
+
+Example:
+
+Given binary tree [3,9,20,null,null,15,7],
+
+ 3
+ / \
+ 9 20
+ / \
+ 15 7
+return its depth = 3.
+
+*/
+
+/*
+Thinking process:
+check if root is null, return 0 if so.
+Divide and return integer as the depth
+Conquer: find the max and return depth + 1.
+*/
+
+/**
+ * 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 maxDepth(TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+ return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/1040. Moving Stones Until Consecutive II.java b/Java/1040. Moving Stones Until Consecutive II.java
new file mode 100755
index 0000000..0e29c0f
--- /dev/null
+++ b/Java/1040. Moving Stones Until Consecutive II.java
@@ -0,0 +1,99 @@
+M
+tags: Sliding Window, Array
+time: O(nlogn)
+space: O(n)
+
+
+#### Analyze to understand
+- Make sure to sort array: we need to use the actual number range `A[j] - A[i]`, which requires the array to be sorted
+- we want to form a new array where A[n-1] - A[0] + 1 == n; order does not matter but all slots need to be filled consecutivly
+- max moves: https://leetcode.com/problems/moving-stones-until-consecutive-ii/discuss/289357/c%2B%2B-with-picture
+ - A interval will be automatically dropped between A[0] and A[1], if moving A[0] first
+ - Same, a interval between A[n-2] and A[n-1] will be dropped when moving A[n-1] first
+ - so largest possible move = firstItem + remaining range size - n items = 1 + (A[n-1] - A[1] + 1) - n = A[n-1] - A[1] -n + 2
+ - or A[n-2] - A[0] - n + 2
+- min moves: `Sliding Window`
+ - use slinding window to assume a right pointer, to make sure A[right] - A[left] + 1 < n; otherwise, move left++
+ - check # of included stones
+ - calculate remaining, which is remaining moves
+- Handle min move edge case:
+ - Consecutive Array up to right = n - 1; need 2 moves to finish
+
+```
+/**
+On an infinite number line, the position of the i-th stone is given by stones[i]. Call a stone an endpoint stone if it has the smallest or largest position.
+
+Each turn, you pick up an endpoint stone and move it to an unoccupied position so that it is no longer an endpoint stone.
+
+In particular, if the stones are at say, stones = [1,2,5], you cannot move the endpoint stone at position 5, since moving it to any position (such as 0, or 3) will still keep that stone as an endpoint stone.
+
+The game ends when you cannot make any more moves, ie. the stones are in consecutive positions.
+
+When the game ends, what is the minimum and maximum number of moves that you could have made? Return the answer as an length 2 array: answer = [minimum_moves, maximum_moves]
+
+
+
+Example 1:
+
+Input: [7,4,9]
+Output: [1,2]
+Explanation:
+We can move 4 -> 8 for one move to finish the game.
+Or, we can move 9 -> 5, 4 -> 6 for two moves to finish the game.
+Example 2:
+
+Input: [6,5,4,3,10]
+Output: [2,3]
+We can move 3 -> 8 then 10 -> 7 to finish the game.
+Or, we can move 3 -> 7, 4 -> 8, 5 -> 9 to finish the game.
+Notice we cannot move 10 -> 2 to finish the game, because that would be an illegal move.
+Example 3:
+
+Input: [100,101,104,102,103]
+Output: [0,0]
+
+
+Note:
+
+3 <= stones.length <= 10^4
+1 <= stones[i] <= 10^9
+stones[i] have distinct values.
+*/
+
+/*
+Analyze to understand:
+- we want to form a new array where A[n-1] - A[0] + 1 == n; order does not matter but all slots need to be filled consecutivly
+- max moves: https://leetcode.com/problems/moving-stones-until-consecutive-ii/discuss/289357/c%2B%2B-with-picture
+ - A interval will be automatically dropped between A[0] and A[1], if moving A[0] first
+ - Same, a interval between A[n-2] and A[n-1] will be dropped when moving A[n-1] first
+ - so largest possible move = firstItem + remaining range size - n items = 1 + (A[n-1] - A[1] + 1) - n = A[n-1] - A[1] -n + 2
+ - or A[n-2] - A[0] - n + 2
+- min moves:
+ - use slinding window to assume a right pointer, to make sure A[right] - A[left] + 1 < n; otherwise, move left++
+ - check # of included stones
+ - calculate remaining, which is remaining moves
+- Handle min move edge case:
+ - Consecutive Array up to right = n - 1; need 2 moves to finish
+*/
+class Solution {
+ public int[] numMovesStonesII(int[] stones) {
+ Arrays.sort(stones);
+
+ int n = stones.length, left = 0, right = 0, min = n;
+ int max = Math.max(stones[n - 1] - stones[1] - n + 2, stones[n - 2] - stones[0] - n + 2);
+
+ while (right < n) {
+ while (stones[right] - stones[left] + 1 > n) left++;
+ int count = right - left + 1;
+ if (count == n - 1 && stones[right] - stones[left] + 1 == n - 1) {
+ min = Math.min(min, 2);
+ } else {
+ min = Math.min(min, n - count);
+ }
+ right++;
+ }
+
+ return new int[]{min, max};
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1041. Robot Bounded In Circle.java b/Java/1041. Robot Bounded In Circle.java
new file mode 100755
index 0000000..f83aaee
--- /dev/null
+++ b/Java/1041. Robot Bounded In Circle.java
@@ -0,0 +1,102 @@
+E
+tags: String
+
+简单的character checking. 各个方向, 加加减减.
+
+```
+/*
+On an infinite plane, a robot initially stands at (0, 0) and faces north. The robot can receive one of three instructions:
+
+"G": go straight 1 unit;
+"L": turn 90 degrees to the left;
+"R": turn 90 degress to the right.
+The robot performs the instructions given in order, and repeats them forever.
+
+Return true if and only if there exists a circle in the plane such that the robot never leaves the circle.
+
+
+
+Example 1:
+
+Input: "GGLLGG"
+Output: true
+Explanation:
+The robot moves from (0,0) to (0,2), turns 180 degrees, and then returns to (0,0).
+When repeating these instructions, the robot remains in the circle of radius 2 centered at the origin.
+Example 2:
+
+Input: "GG"
+Output: false
+Explanation:
+The robot moves north indefinitely.
+Example 3:
+
+Input: "GL"
+Output: true
+Explanation:
+The robot moves from (0, 0) -> (0, 1) -> (-1, 1) -> (-1, 0) -> (0, 0) -> ...
+
+
+Note:
+
+1 <= instructions.length <= 100
+instructions[i] is in {'G', 'L', 'R'}
+
+*/
+
+//TODO
+
+
+
+/*
+// LintCode:
+Initially, there is a Robot at position (0, 0).
+Given a sequence of its moves, judge if this robot makes a circle,
+which means it moves back to the original place.
+
+The move sequence is represented by a string.
+And each move is represent by a character.
+The valid robot moves are R (Right), L (Left), U (Up) and D (down).
+The output should be true or false representing whether the robot makes a circle.
+
+Example 1:
+Input: "UD"
+Output: true
+Example 2:
+Input: "LL"
+Output: false
+*/
+
+/*
+Thoughts:
+Each letter represent a movement:
+U: {0, 1}
+D: {0, -1}
+R: {1, 0}
+L: {-1, 0}
+Just add them all together O(n).
+
+Or, even easier:
+Add all of U && D; check if equal to 0.
+Add all of R && L; check if equal to 0
+*/
+
+class Solution {
+ public boolean judgeCircle(String moves) {
+ if (moves == null || moves.length() % 2 == 1) {
+ return false;
+ }
+ int trackX = 0;
+ int trackY = 0;
+ for (int i = 0; i < moves.length(); i++) {
+ if (moves.charAt(i) == 'U' || moves.charAt(i) == 'D') {
+ trackY += moves.charAt(i) == 'U' ? 1 : -1;
+ }
+ if (moves.charAt(i) == 'L' || moves.charAt(i) == 'R') {
+ trackX += moves.charAt(i) == 'L' ? 1 : -1;
+ }
+ }
+ return trackX == 0 && trackY == 0;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1043. Partition Array for Maximum Sum.java b/Java/1043. Partition Array for Maximum Sum.java
new file mode 100755
index 0000000..46fd270
--- /dev/null
+++ b/Java/1043. Partition Array for Maximum Sum.java
@@ -0,0 +1,56 @@
+M
+tags: Memoization, DFS, DP, Graph
+time: O(n), calc memo[n]
+space: O(n)
+
+#### Top-Down DFS + Memoization
+- Pick a subset (max-size k), and produce sub problem to solve by dfs
+- NOTE: no need to change actual index value. That makes this problem easier (no need to record the choice path)
+- time: O(n), calc memo[n]
+- space: O(n), memo + stack depth
+
+```
+/*
+Given an integer array A, you partition the array into (contiguous) subarrays of length at most K. After partitioning, each subarray has their values changed to become the maximum value of that subarray.
+
+Return the largest sum of the given array after partitioning.
+
+
+
+Example 1:
+
+Input: A = [1,15,7,9,2,5,10], K = 3
+Output: 84
+Explanation: A becomes [15,15,15,9,10,10,10]
+
+
+Note:
+
+1 <= K <= A.length <= 500
+0 <= A[i] <= 10^6
+*/
+
+class Solution {
+ Integer[] memo;
+ public int maxSumAfterPartitioning(int[] A, int K) {
+ if (A == null || A.length == 0) return 0;
+
+ int n = A.length;
+ memo = new Integer[n];
+ return dfs(A, K, 0);
+ }
+
+ private int dfs(int[] A, int k, int index) {
+ if (index >= A.length) return 0;
+ if (memo[index] != null) return memo[index];
+
+ int local = Integer.MIN_VALUE, max = Integer.MIN_VALUE;
+ for (int i = index; i < A.length && i < index + k; i++) {
+ local = Math.max(local, A[i]);
+ max = Math.max(max, local * (i - index + 1) + dfs(A, k, i + 1));
+ }
+ memo[index] = max;
+ return max;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1048. Longest String Chain.java b/Java/1048. Longest String Chain.java
new file mode 100755
index 0000000..c5f2f4f
--- /dev/null
+++ b/Java/1048. Longest String Chain.java
@@ -0,0 +1,109 @@
+M
+tags: Hash Table, DP, Sort, Bucket Sort
+time: O(n)
+space: O(n)
+
+#### Hash table, DP
+- store `Map`
+- sort all words, try from short to long: short word will be calculated first to serve later words as candidate
+- time: O(nlogn)
+- space: O(n)
+
+#### Hash Table, Bucket Sort,DP
+- store `Bucket: List[17] of words`, given word size limit [0 ~ 16]
+- time: O(n)
+- space: O(n)
+
+```
+/*
+Given a list of words, each word consists of English lowercase letters.
+
+Let's say word1 is a predecessor of word2 if and only if we can add exactly one letter anywhere in word1 to make it equal to word2. For example, "abc" is a predecessor of "abac".
+
+A word chain is a sequence of words [word_1, word_2, ..., word_k] with k >= 1, where word_1 is a predecessor of word_2, word_2 is a predecessor of word_3, and so on.
+
+Return the longest possible length of a word chain with words chosen from the given list of words.
+
+
+
+Example 1:
+
+Input: ["a","b","ba","bca","bda","bdca"]
+Output: 4
+Explanation: one of the longest word chain is "a","ba","bda","bdca".
+
+
+Note:
+
+1 <= words.length <= 1000
+1 <= words[i].length <= 16
+words[i] only consists of English lowercase letters.
+*/
+/*
+Method1: sort, HashMap, DP
+- store Map
+- sort all words, try from short to long: short word will be calculated first to serve later words as candidate
+- time: O(nlogn)
+- space: O(n)
+*/
+class Solution {
+ public int longestStrChain(String[] words) {
+ int rst = 0;
+ Arrays.sort(words, Comparator.comparing(a -> a.length()));
+ HashMap wordChainMap = new HashMap();
+ for (String word : words) {
+ if (wordChainMap.containsKey(word)) continue;
+ wordChainMap.put(word, 1);
+ for (int i = 0; i < word.length(); i++) {
+ StringBuilder sb = new StringBuilder(word);
+ sb.deleteCharAt(i);
+ String lastWord = sb.toString();
+ if (wordChainMap.containsKey(lastWord) && wordChainMap.get(lastWord) + 1 > wordChainMap.get(word)) {
+ wordChainMap.put(word, wordChainMap.get(lastWord) + 1);
+ }
+ }
+ if (wordChainMap.get(word) > rst) rst = wordChainMap.get(word);
+ }
+ return rst;
+ }
+}
+
+// Method2: bucket sort O(n) time
+class Solution {
+ public int longestStrChain(String[] words) {
+ int rst = 0;
+
+ List[] bucket = buildBucket(words);
+ HashMap map = new HashMap();
+
+ for (List list : bucket) {
+ if (list == null) continue;
+ for (String word : list) {
+ if (map.containsKey(word)) continue;
+ map.put(word, 1);
+ for (int i = 0; i < word.length(); i++) {
+ StringBuilder sb = new StringBuilder(word);
+ sb.deleteCharAt(i);
+ String lastWord = sb.toString();
+ if (map.containsKey(lastWord) && map.get(lastWord) + 1 > map.get(word)) {
+ map.put(word, map.get(lastWord) + 1);
+ }
+ }
+ if (map.get(word) > rst) rst = map.get(word);
+ }
+ }
+ return rst;
+ }
+
+ // O(n)
+ private List[] buildBucket(String[] words) {
+ List[] bucket = new List[17];
+ for (String w : words) {
+ int len = w.length();
+ if (bucket[len] == null) bucket[len] = new ArrayList<>();
+ bucket[len].add(w);
+ }
+ return bucket;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/105. Construct Binary Tree from Preorder and Inorder Traversal.java b/Java/105. Construct Binary Tree from Preorder and Inorder Traversal.java
new file mode 100755
index 0000000..a2c125c
--- /dev/null
+++ b/Java/105. Construct Binary Tree from Preorder and Inorder Traversal.java
@@ -0,0 +1,152 @@
+M
+tags: Array, Tree, DFS, Divide and Conquer, Hash Table
+time: O(n)
+space: O(n)
+
+如题
+
+#### DFS ApproachA:
+- use preorder to find root, one index at a time (global index)
+- use the root to divide and conquer inorder int[] to 2 sides;
+ - root.left = dfs(left); root.right = dfs(right)
+ - end stage: start == end index, create a node
+- can use a map to store inorder for O(1) find
+
+#### DFS
+- 和Construct from Inorder && Postorder 想法一样。
+- 写出Preorder和Inorder的字母例子,发现Preorder的开头总是这Level的root。依此写helper,注意处理index。
+- 跟Convert Sorted Array to Binary Tree类似, 找到对应的index, 然后:
+ - node.left = dfs(...), node.right = dfs(...)
+- Divide and Conquer
+ - optimize on finding `mid node`: given value, find mid of inorder:
+- Instead of searching linearly, just store inorder sequence in `map index>`, O(1)
+- IMPORATANT: the mid from inorder sequence will become the main baseline to tell range:
+- `range of subTree = (mid - inStart)`
+- sapce: O(n), time: O(n) access
+
+```
+/*
+Given preorder and inorder traversal of a tree, construct the binary tree.
+
+Note
+You may assume that duplicates do not exist in the tree.
+
+Example
+Given inorder [1,2,3] and preorder [2,1,3]
+
+return a tree
+
+ 2
+
+ / \
+
+1 3
+
+Tags Expand
+Binary Tree
+*/
+
+
+/*
+- use preorder to find root, 1 index at a time
+- use the root to divide and conquer inorder int[] to 2 sides;
+ - root.left = dfs(left); root.right = dfs(right)
+ - end stage: start == end index, create a node
+- can use a map to store inorder for O(1) find
+*/
+class Solution {
+ int index = 0;
+ Map map;
+ public TreeNode buildTree(int[] preorder, int[] inorder) {
+ if (preorder == null || inorder == null || preorder.length == 0
+ || preorder.length != inorder.length) return null;
+ map = buildMap(inorder);
+ return dfs(inorder, preorder, 0, inorder.length - 1);
+ }
+
+ public TreeNode dfs(int[] inorder, int[] preorder, int start, int end) {
+ if (start > end) return null; // catch dfs attempting to process visisted nodes
+ int rootVal = preorder[index++];
+ int rootInd = map.get(rootVal);
+ TreeNode root = new TreeNode(rootVal);
+ if (start == end) return root;
+
+ root.left = dfs(inorder, preorder, start, rootInd - 1);
+ root.right = dfs(inorder, preorder, rootInd + 1, end);
+
+ return root;
+ }
+
+ private Map buildMap(int[] inorder) {
+ Map map = new HashMap<>();
+ for (int i = 0; i < inorder.length; i++) map.put(inorder[i], i);
+ return map;
+ }
+}
+
+ /*
+Thougths:
+DFS with tracking of preorder/inorder sequence indexes.
+preorder: start from root, traverse all left children, and then all right children.
+inorder: if found the root node in the sequence, all indexes less than the root is left sub tree; same applies to right indexes.
+
+1. Use preorder head index as root
+2. Find the root node index in inorder sequence.
+3. split into subproblems: track by indexes
+*//**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+ class Solution {
+ Map map;
+ public TreeNode buildTree(int[] preorder, int[] inorder) {
+ if (preorder == null || inorder == null || preorder.length == 0
+ || preorder.length != inorder.length) return null;
+ map = buildMap(inorder);
+ int n = preorder.length;
+ return dfs(preorder, 0, n - 1, inorder, 0, n - 1);
+ }
+
+ public TreeNode dfs(int[] preorder, int preStart, int preEnd,
+ int[] inorder, int inStart, int inEnd) {
+ if (preStart > preEnd) return null;
+ TreeNode root = new TreeNode(preorder[preStart]);
+ int rootInd = map.get(preorder[preStart]);
+
+ if (rootInd < 0) return null;
+
+ //root.left
+ root.left = dfs(preorder, preStart + 1, preStart + (rootInd - inStart),
+ inorder, inStart, rootInd - 1);
+ //root.right
+ root.right = dfs(preorder, preStart + (rootInd - inStart) + 1, preEnd,
+ inorder, rootInd + 1, inEnd);
+
+ return root;
+ }
+
+ private Map buildMap(int[] inorder) {
+ Map map = new HashMap<>();
+ for (int i = 0; i < inorder.length; i++) map.put(inorder[i], i);
+ return map;
+ }
+}
+
+
+/**
+ * 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;
+ * }
+ * }
+ */
+```
diff --git a/Java/1053. Previous Permutation With One Swap.java b/Java/1053. Previous Permutation With One Swap.java
new file mode 100755
index 0000000..d2d1536
--- /dev/null
+++ b/Java/1053. Previous Permutation With One Swap.java
@@ -0,0 +1,75 @@
+M
+tags: Array, Greedy, Permutation
+time: O(n)
+space: O(1)
+
+#### Analyze Permutation behavior
+- concept similar to `31. Next Permutation`
+- 1) first pass: find the one that is in incorrect order
+- 2) second pass: find the right spot to swap
+
+```
+/*
+Given an array A of positive integers (not necessarily distinct), return the lexicographically largest permutation that is smaller than A, that can be made with one swap (A swap exchanges the positions of two numbers A[i] and A[j]). If it cannot be done, then return the same array.
+
+
+
+Example 1:
+
+Input: [3,2,1]
+Output: [3,1,2]
+Explanation: Swapping 2 and 1.
+Example 2:
+
+Input: [1,1,5]
+Output: [1,1,5]
+Explanation: This is already the smallest permutation.
+Example 3:
+
+Input: [1,9,4,6,7]
+Output: [1,7,4,6,9]
+Explanation: Swapping 9 and 7.
+Example 4:
+
+Input: [3,1,1,3]
+Output: [1,3,1,3]
+Explanation: Swapping 1 and 3.
+
+
+Note:
+
+1 <= A.length <= 10000
+1 <= A[i] <= 10000
+*/
+
+class Solution {
+ public int[] prevPermOpt1(int[] A) {
+ if (A.length <= 1) return A;
+ int index = -1;
+ // find the largest i such that A[i] > A[i + 1]
+ for (int i = A.length - 1; i >= 1; i--) {
+ if (A[i] < A[i - 1]) {
+ index = i - 1;
+ break;
+ }
+ }
+ // the array already sorted ascendingly, no need to procceed
+ if (index == -1) return A;
+
+ // find the largest i such that A[index] > A[i], then swap them
+ for (int i = A.length - 1; i > index; i--) {
+ if (A[i] < A[index] && A[i] != A[i - 1]) {
+ swap(A, i, index);
+ break;
+ }
+ }
+ return A;
+ }
+
+ private void swap(int[] arr, int x, int y) {
+ int temp = arr[x];
+ arr[x] = arr[y];
+ arr[y] = temp;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1057. Campus Bikes.java b/Java/1057. Campus Bikes.java
new file mode 100755
index 0000000..d6f064e
--- /dev/null
+++ b/Java/1057. Campus Bikes.java
@@ -0,0 +1,177 @@
+M
+tags: Greedy, Sort, PriorityQueue, Bucket Sort
+time: O(mn)
+space: O(mn)
+
+#### Method1: PriorityQueue
+- PQ can be used to sort on multiple attributes
+- follow the specified rules, and build all possible pairs of visits vs. bike. Pair {int dist, workerIndex, bikeIndex}
+- PQ to sort them
+ - first by dist
+ - if same dist, sort by workerIndex
+ - if same workderIndex, sort by bikeIndex
+- process all candidates, and skip the ones (workers/bikes) visited
+
+#### Method2: Bucket Sort
+- Similar to using PQ: the goal is to find: 1) min dist; 2) closer worker index, 3) closer bike index
+- can use bucket sort to hold all possible distances [0 ~ 2000]: bucket[List of pairs]
+ - do a hard iteration (ordered access from min dist).
+- time: O(mn), no need to sort
+- space: O(mn)
+
+```
+/*
+
+On a campus represented as a 2D grid, there are N workers and M bikes, with N <= M. Each worker and bike is a 2D coordinate on this grid.
+
+Our goal is to assign a bike to each worker. Among the available bikes and workers, we choose the (worker, bike) pair with the shortest Manhattan distance between each other, and assign the bike to that worker. (If there are multiple (worker, bike) pairs with the same shortest Manhattan distance, we choose the pair with the smallest worker index; if there are multiple ways to do that, we choose the pair with the smallest bike index). We repeat this process until there are no available workers.
+
+The Manhattan distance between two points p1 and p2 is Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|.
+
+Return a vector ans of length N, where ans[i] is the index (0-indexed) of the bike that the i-th worker is assigned to.
+
+
+
+Example 1:
+
+
+
+Input: workers = [[0,0],[2,1]], bikes = [[1,2],[3,3]]
+Output: [1,0]
+Explanation:
+Worker 1 grabs Bike 0 as they are closest (without ties), and Worker 0 is assigned Bike 1. So the output is [1, 0].
+Example 2:
+
+
+
+Input: workers = [[0,0],[1,1],[2,0]], bikes = [[1,0],[2,2],[2,1]]
+Output: [0,2,1]
+Explanation:
+Worker 0 grabs Bike 0 at first. Worker 1 and Worker 2 share the same distance to Bike 2, thus Worker 1 is assigned to Bike 2, and Worker 2 will take Bike 1. So the output is [0,2,1].
+
+
+Note:
+
+0 <= workers[i][j], bikes[i][j] < 1000
+All worker and bike locations are distinct.
+1 <= workers.length <= bikes.length <= 1000
+*/
+/*
+- follow the specified rules, and build all possible pairs of visits vs. bike. Pair {int dist, workerIndex, bikeIndex}
+- PQ to sort them
+ - first by dist
+ - if same dist, sort by workerIndex
+ - if same workderIndex, sort by bikeIndex
+- process all candidates, and skip the ones (workers/bikes) visited
+*/
+class Solution {
+ class Pair {
+ int dist, i, j; // i = workder index, j = bikeIndex
+ public Pair(int dist, int i, int j) {
+ this.i = i;
+ this.j = j;
+ this.dist = dist;
+ }
+ }
+ public int[] assignBikes(int[][] workers, int[][] bikes) {
+
+ PriorityQueue queue = buildQueue();
+
+ int n = workers.length, m = bikes.length;
+ for (int i = 0; i < n; i++) {
+ int[] worker = workers[i];
+ for (int j = 0; j < m; j++) {
+ int[] bike = bikes[j];
+ int dist = Math.abs(worker[0] - bike[0]) + Math.abs(worker[1] - bike[1]);
+ queue.offer(new Pair(dist, i, j));
+ }
+ }
+
+ Set visitedBike = new HashSet<>();
+ int[] rst = new int[n];
+ Arrays.fill(rst, -1);
+ while (visitedBike.size() < n) {
+ Pair p = queue.poll();
+ if (rst[p.i] == -1 && !visitedBike.contains(p.j)) {
+ rst[p.i] = p.j;
+ visitedBike.add(p.j);
+ }
+ }
+
+ return rst;
+ }
+
+ private PriorityQueue buildQueue() {
+ return new PriorityQueue<>(new Comparator() {
+ public int compare(Pair p1, Pair p2) {
+ int comp = Integer.compare(p1.dist, p2.dist);
+ if (comp == 0) {
+ comp = Integer.compare(p1.i, p2.i); // compare worker index
+ if (comp == 0) return Integer.compare(p1.j, p2.j); // compare bike index
+ return comp;
+ }
+ return comp;
+ }
+ });
+ }
+}
+
+
+/*
+Method2: Bucket Sort
+- Similar to using PQ: the goal is to find: 1) min dist; 2) closer worker index, 3) closer bike index
+- can use bucket sort to hold all possible distances [0 ~ 2000]: bucket[List of pairs]
+ - do a hard iteration (ordered access from min dist).
+- follow the specified rules, and build all possible pairs of visits vs. bike. Pair {int dist, workerIndex, bikeIndex}
+- PQ to sort them
+ - first by dist
+ - if same dist, sort by workerIndex
+ - if same workderIndex, sort by bikeIndex
+- process all candidates, and skip the ones (workers/bikes) visited
+*/
+class Solution {
+ class Pair {
+ int dist, i, j; // i = workder index, j = bikeIndex
+ public Pair(int dist, int i, int j) {
+ this.i = i;
+ this.j = j;
+ this.dist = dist;
+ }
+ }
+ public int[] assignBikes(int[][] workers, int[][] bikes) {
+ List[] bucket = buildBucket(workers, bikes);
+ Set visitedBike = new HashSet<>();
+ int[] rst = new int[workers.length];
+ Arrays.fill(rst, -1);
+
+ for (int dist = 0; dist < bucket.length; dist++) {
+ List list = bucket[dist];
+ if (list == null) continue;
+ for (Pair p : list) {
+ if (rst[p.i] == -1 && !visitedBike.contains(p.j)) {
+ rst[p.i] = p.j;
+ visitedBike.add(p.j);
+ }
+ }
+ }
+ return rst;
+ }
+
+ private List[] buildBucket(int[][] workers, int[][] bikes) {
+ List[] bucket = new List[2001];
+ int n = workers.length, m = bikes.length;
+ for (int i = 0; i < n; i++) {
+ int[] worker = workers[i];
+ for (int j = 0; j < m; j++) {
+ int[] bike = bikes[j];
+ int dist = Math.abs(worker[0] - bike[0]) + Math.abs(worker[1] - bike[1]);
+ if (bucket[dist] == null) bucket[dist] = new ArrayList<>();
+ bucket[dist].add(new Pair(dist, i, j));
+ }
+ }
+
+ return bucket;
+ }
+
+}
+```
\ No newline at end of file
diff --git a/Java/1060. Missing Element in Sorted Array.java b/Java/1060. Missing Element in Sorted Array.java
new file mode 100755
index 0000000..73e818d
--- /dev/null
+++ b/Java/1060. Missing Element in Sorted Array.java
@@ -0,0 +1,94 @@
+M
+tags: Binary Search
+time: O(logn)
+space: O(1)
+
+#### Binary Search
+- total missing nums = nums[curr] - nums[0] - curr
+- edge case: if k > total missing nums, then just add the diff from nums[end]
+- otherwise, find this `missing count == k` in the nums using binary search
+- After binary search: `start + 1 == end`:
+ - re-calculate `count = nums[start] - nums[0] - start;`
+ - output final num: `nums[start] + k - count;`
+- Option1: always compare total missing nums count
+- Option2: compare partial missing nums count (inspired by: https://leetcode.com/problems/missing-element-in-sorted-array/discuss/303444/Java-O(logN)-solution-Binary-Search)
+
+
+```
+/*
+
+Given a sorted array A of unique numbers, find the K-th missing number starting from the leftmost number of the array.
+
+
+
+Example 1:
+
+Input: A = [4,7,9,10], K = 1
+Output: 5
+Explanation:
+The first missing number is 5.
+Example 2:
+
+Input: A = [4,7,9,10], K = 3
+Output: 8
+Explanation:
+The missing numbers are [5,6,8,...], hence the third missing number is 8.
+Example 3:
+
+Input: A = [1,2,4], K = 3
+Output: 6
+Explanation:
+The missing numbers are [3,5,6,7,...], hence the third missing number is 6.
+
+
+Note:
+
+1 <= A.length <= 50000
+1 <= A[i] <= 1e7
+1 <= K <= 1e8
+
+*/
+// Binary Search, Option1: always compare total missing nums
+class Solution {
+ public int missingElement(int[] nums, int k) {
+ int start = 0, end = nums.length - 1;
+ int count = nums[end] - nums[0] - end;
+ if (count < k) {
+ return nums[end] + k - count;
+ }
+
+ while (start + 1 < end) {
+ int mid = start + (end - start) / 2;
+ count = nums[mid] - nums[0] - mid;
+ if (count >= k) end = mid;
+ else start = mid;
+ }
+ count = nums[start] - nums[0] - start;
+ return nums[start] + k - count;
+ }
+}
+
+// Binary Search, Option1: always compare pairtial missing nums in range [mid, end]
+class Solution {
+ public int missingElement(int[] nums, int k) {
+
+ int start = 0, end = nums.length - 1;
+ int count = nums[end] - nums[0] - end;
+ if (count < k) {
+ return nums[end] + k - count;
+ }
+
+ while (start + 1 < end) {
+ int mid = start + (end - start) / 2;
+ count = nums[mid] - nums[start] - (mid - start);
+ if (count >= k) {
+ end = mid;
+ } else {
+ start = mid;
+ k -= count;
+ }
+ }
+ return nums[start] + k;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1091. Shortest Path in Binary Matrix.java b/Java/1091. Shortest Path in Binary Matrix.java
new file mode 100755
index 0000000..da4c612
--- /dev/null
+++ b/Java/1091. Shortest Path in Binary Matrix.java
@@ -0,0 +1,90 @@
+M
+tags: BFS
+time: O(n^2)
+time: O(n^2)
+
+
+#### BFS
+- find shortest path using queue
+- time/space: O(n^2), n = grid length
+- why SKIP `boolean visited[i][j]`? after a position grid[i][j] is used:
+ - 1) the curr path will not return to (i, j)
+ - 2) other route that may eventually reach (i, j) need not to be recorded,
+ - because the other route is already longer than the curr path
+ - therefore, we just simply block the visited node by `grid[x][y] = 1`
+ - note: block it right after it is added to the queue, so other nodes at same level will not attempt this visited node.
+
+```
+
+
+/*
+In an N by N square grid, each cell is either empty (0) or blocked (1).
+
+A clear path from top-left to bottom-right has length k if and only if it is composed of cells C_1, C_2, ..., C_k such that:
+
+Adjacent cells C_i and C_{i+1} are connected 8-directionally (ie., they are different and share an edge or corner)
+C_1 is at location (0, 0) (ie. has value grid[0][0])
+C_k is at location (N-1, N-1) (ie. has value grid[N-1][N-1])
+If C_i is located at (r, c), then grid[r][c] is empty (ie. grid[r][c] == 0).
+Return the length of the shortest such clear path from top-left to bottom-right. If such a path does not exist, return -1.
+
+
+
+Example 1:
+
+Input: [[0,1],[1,0]]
+
+
+Output: 2
+
+Example 2:
+
+Input: [[0,0,0],[1,1,0],[1,1,0]]
+
+
+Output: 4
+
+
+
+Note:
+
+1 <= grid.length == grid[0].length <= 100
+grid[r][c] is 0 or 1
+
+*/
+
+class Solution {
+ int[] dx = new int[]{-1, -1, -1, 0, 0, 1, 1, 1};
+ int[] dy = new int[]{-1, 0, 1, -1, 1, -1, 0, 1};
+ int N;
+ public int shortestPathBinaryMatrix(int[][] grid) {
+ N = grid.length;
+ Queue queue = new LinkedList<>();
+ if (grid[0][0] == 0) queue.offer(new int[] {0, 0});
+ grid[0][0] = 1;
+ int depth = 1;
+
+ while (!queue.isEmpty()) {
+ int size = queue.size();
+ while (size-- > 0) {
+ int[] pos = queue.poll();
+
+ if (pos[0] == N - 1 && pos[1] == N -1) return depth;
+ for (int i = 0; i < dx.length; i++) {
+ int x = pos[0] + dx[i], y = pos[1] + dy[i];
+ if (validate(grid, x, y)) {
+ queue.offer(new int[] {x, y});
+ grid[x][y] = 1;
+ }
+ }
+ }
+ depth++;
+ }
+ return -1;
+ }
+
+ private boolean validate(int[][] grid, int i, int j) {
+ return (i >= 0 && i < N && j >= 0 && j < N && grid[i][j] == 0);
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/1094. Car Pooling.java b/Java/1094. Car Pooling.java
new file mode 100755
index 0000000..193b208
--- /dev/null
+++ b/Java/1094. Car Pooling.java
@@ -0,0 +1,112 @@
+M
+tags: PriorityQueue, Heap, Sort, Greedy
+time: O(n)
+space: O(1) only use bucket size 1000
+
+#### Method1: bucket sort
+- define the bucket by index: the total distance is fixed [0, 1000]
+- +/- capacities for each pos and save into the bucket
+- go over the bucket and see if the total cap goes over input capacity
+- O(n), trips size
+- space: O(1), bucket size 1000 is constant
+- `IMPORTANT`: before using PQ to sort, consider bucket sort:
+ - if the boundary set and seems resonable? i.e., max size = `1000`
+ - is the sorted items index based?
+
+#### Method2: Priority Queue, sort distnace
+- Like meeting room, merge interval
+- process items on same index
+
+```
+/*
+You are driving a vehicle that has capacity empty seats initially available for passengers. The vehicle only drives east (ie. it cannot turn around and drive west.)
+
+Given a list of trips, trip[i] = [num_passengers, start_location, end_location] contains information about the i-th trip: the number of passengers that must be picked up, and the locations to pick them up and drop them off. The locations are given as the number of kilometers due east from your vehicle's initial location.
+
+Return true if and only if it is possible to pick up and drop off all passengers for all the given trips.
+
+
+
+Example 1:
+
+Input: trips = [[2,1,5],[3,3,7]], capacity = 4
+Output: false
+Example 2:
+
+Input: trips = [[2,1,5],[3,3,7]], capacity = 5
+Output: true
+Example 3:
+
+Input: trips = [[2,1,5],[3,5,7]], capacity = 3
+Output: true
+Example 4:
+
+Input: trips = [[3,2,7],[3,7,9],[8,3,9]], capacity = 11
+Output: true
+
+
+
+Constraints:
+
+trips.length <= 1000
+trips[i].length == 3
+1 <= trips[i][0] <= 100
+0 <= trips[i][1] < trips[i][2] <= 1000
+1 <= capacity <= 100000
+*/
+
+
+/*
+Method1: bucket sort
+- define the bucket by index: the total distance is fixed [0, 1000]
+- +/- capacities for each pos and save into the bucket
+- go over the bucket and see if the total cap goes over input capacity
+- O(n), n = trips size
+*/
+class Solution {
+ public boolean carPooling(int[][] trips, int capacity) {
+ if (trips == null || trips.length == 0) return true;
+
+ int[] bucket = new int[1000];
+ for (int[] trip : trips) {
+ bucket[trip[1]] += trip[0];
+ bucket[trip[2]] += -trip[0];
+ }
+ int cap = 0;
+ for (int num : bucket) {
+ cap += num;
+ if (cap > capacity) return false;
+ }
+ return true;
+ }
+
+}
+
+// Method2: Priority Queue, sort distnace
+class Solution {
+ public boolean carPooling(int[][] trips, int capacity) {
+ if (trips == null || trips.length == 0) return true;
+
+ PriorityQueue queue = buildQueue(trips);
+ int cap = 0;
+ while (!queue.isEmpty()) {
+ int[] point = queue.poll();
+ cap += point[1];
+ while (!queue.isEmpty() && queue.peek()[0] == point[0]) {
+ cap += queue.poll()[1];
+ }
+ if (cap > capacity) return false;
+ }
+ return true;
+ }
+
+ private PriorityQueue buildQueue(int[][] trips) {
+ PriorityQueue queue = new PriorityQueue<>(Comparator.comparing(p -> p[0]));
+ for (int[] trip : trips) {
+ queue.offer(new int[]{trip[1], trip[0]});
+ queue.offer(new int[]{trip[2], -trip[0]});
+ }
+ return queue;
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/110. Balanced Binary Tree.java b/Java/110. Balanced Binary Tree.java
new file mode 100755
index 0000000..61230fb
--- /dev/null
+++ b/Java/110. Balanced Binary Tree.java
@@ -0,0 +1,101 @@
+E
+tags: Tree, DFS
+
+给一个binary tree, 看是否是height-balanced
+
+#### DFS with end state
+- 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 above solution, but cost more traversal efforts
+- 试图计算所有情况
+
+```
+/*
+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.
+
+Example
+Given binary tree A={3,9,20,#,#,15,7}, B={3,#,20,15,7}
+
+A) 3 B) 3
+ / \ \
+ 9 20 20
+ / \ / \
+ 15 7 15 7
+The binary tree A is a height-balanced binary tree, but B is not.
+
+Tags Expand
+Binary Search Divide and Conquer Recursion
+
+*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+
+/*
+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.
+*/
+class Solution {
+ public boolean isBalanced(TreeNode root) {
+ if (root == null) return true;
+ return calDepth(root) > 0;
+ }
+
+ private int calDepth(TreeNode node) {
+ if (node == null) return 0;
+ int leftDepth = calDepth(node.left);
+ int rightDepth = calDepth(node.right);
+ if (leftDepth < 0 || rightDepth < 0 || (Math.abs(leftDepth - rightDepth)) > 1) {
+ return Integer.MIN_VALUE;
+ }
+ 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);
+
+ 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;
+ }
+}
+
+
+
+
+```
\ No newline at end of file
diff --git a/Java/1106. Parsing A Boolean Expression.java b/Java/1106. Parsing A Boolean Expression.java
new file mode 100755
index 0000000..00c190c
--- /dev/null
+++ b/Java/1106. Parsing A Boolean Expression.java
@@ -0,0 +1,148 @@
+H
+tags: String, Stack, DFS
+
+#### Parse exp as sub problem
+- Analyze the pattern: 1) single char, 2) with !, 3) with &, |
+- Identify sub problem
+ - Use stack to parse the data in "()", which is a sub problem to solve with recursive call
+ - Handle &, | case: need to parse multiple
+- Be comfortable with string parsing
+- Slight improve:
+ - If see obvious result, directly return evaluation w/o further parsing
+ - use memo to store evaluated exp
+
+#### Evaluate inner exp and save back to Stack
+- Use '(' and ')' to mark inner exp
+- Evaluate the inner exp and save result back to Stack: the result will be 'f' or 't'
+- This is slightly slow because:
+ - It requires all stack items on top to be processed before reaching the operator
+ - There is no room to optimize even there is simplification for specific operator
+
+```
+/**
+
+Return the result of evaluating a given boolean expression, represented as a string.
+
+An expression can either be:
+
+"t", evaluating to True;
+"f", evaluating to False;
+"!(expr)", evaluating to the logical NOT of the inner expression expr;
+"&(expr1,expr2,...)", evaluating to the logical AND of 2 or more inner expressions expr1, expr2, ...;
+"|(expr1,expr2,...)", evaluating to the logical OR of 2 or more inner expressions expr1, expr2, ...
+
+
+Example 1:
+
+Input: expression = "!(f)"
+Output: true
+Example 2:
+
+Input: expression = "|(f,t)"
+Output: true
+Example 3:
+
+Input: expression = "&(t,f)"
+Output: false
+Example 4:
+
+Input: expression = "|(&(t,f,t),!(t))"
+Output: false
+
+*/
+class Solution {
+ Map memo = new HashMap<>();
+ public boolean parseBoolExpr(String exp) {
+ if (exp.length() == 1) return exp.equals("t");
+ if (memo.containsKey(exp)) return memo.get(exp);
+
+ char op = exp.charAt(0);
+ String s = exp.substring(2, exp.length() - 1);
+
+ if (op == '!') return !parseBoolExpr(s);
+ // process the inner list of & or |
+ List values = parseBoolExprList(s, op);
+ boolean result = evalList(values, op);
+
+ memo.put(exp, result);
+ return result;
+ }
+
+ // Parse expr list (w/o the outter "(", ")")
+ private List parseBoolExprList(String s, char op) {
+ int i = 0;
+ List values = new ArrayList<>();
+ while (i < s.length()) {
+ char c = s.charAt(i++);
+ if (c == ',') continue;
+
+ // w/o oprator
+ if(c == 't' || c == 'f') values.add(c == 't');
+ else {
+ // extract inner exp block including "(" and ")"
+ String sub = findExpBlock(s, i);
+ i += sub.length();
+
+ // evaluate
+ boolean val = parseBoolExpr(c + sub);
+ values.add(val);
+
+ // optimization
+ if (op == '|' && val) return Arrays.asList(true);
+ if (op == '&' && !val) return Arrays.asList(false);
+ }
+ }
+ return values;
+ }
+
+ private String findExpBlock(String s, int i) {
+ StringBuffer sb = new StringBuffer();
+ Stack stack = new Stack<>();
+ while (sb.length() == 0 || !stack.isEmpty()) {
+ char c = s.charAt(i++);
+ sb.append(c);
+ if (c == '(') stack.push(c);
+ if (c == ')') stack.pop();
+ if (stack.isEmpty()) break;
+ }
+ return sb.toString();
+ }
+
+ private boolean evalList(List list, char op) {
+ if (op == '&') {
+ for (boolean b : list) {
+ if (!b) return false;
+ }
+ return true;
+ }
+ // op == '|'
+ for (boolean b : list) {
+ if (b) return true;
+ }
+ return false;
+ }
+}
+
+
+// Use '(' and ')' to mark start and end, then add eval back to stack
+class Solution {
+ public boolean parseBoolExpr(String exp) {
+ Stack stack = new Stack<>();
+ for (char c : exp.toCharArray()) {
+ if (c == ')') {
+ Set expItems = new HashSet<>();
+ while (stack.peek() != '(') expItems.add(stack.pop());
+ stack.pop(); // pop out '('
+ char op = stack.pop();
+ if (op == '&') stack.push(expItems.contains('f') ? 'f' : 't');
+ else if (op == '|') stack.push(expItems.contains('t') ? 't' : 'f');
+ else if (op == '!') stack.push(expItems.contains('t') ? 'f' : 't');
+ } else if (c != ',') {
+ stack.push(c);
+ }
+ }
+ return stack.pop() == 't';
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/1108. Defanging an IP Address.java b/Java/1108. Defanging an IP Address.java
new file mode 100755
index 0000000..6c5efdb
--- /dev/null
+++ b/Java/1108. Defanging an IP Address.java
@@ -0,0 +1,35 @@
+E
+tags: String, Basic Implementation
+
+```
+
+/**
+Given a valid (IPv4) IP address, return a defanged version of that IP address.
+
+A defanged IP address replaces every period "." with "[.]".
+
+
+
+Example 1:
+
+Input: address = "1.1.1.1"
+Output: "1[.]1[.]1[.]1"
+Example 2:
+
+Input: address = "255.100.50.0"
+Output: "255[.]100[.]50[.]0"
+*/
+class Solution {
+ public String defangIPaddr(String address) {
+ StringBuffer sb = new StringBuffer();
+ for (char c : address.toCharArray()) {
+ if (c == '.') {
+ sb.append("[.]");
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/111. Minimum Depth of Binary Tree.java b/Java/111. Minimum Depth of Binary Tree.java
new file mode 100755
index 0000000..6add7c7
--- /dev/null
+++ b/Java/111. Minimum Depth of Binary Tree.java
@@ -0,0 +1,87 @@
+E
+tags: Tree, DFS, BFS
+time: O(n)
+space: O(n)
+
+#### BFS
+- Shortest path; minimum depth: 想到BFS, check level by level, BFS更能确保更快找到结果
+- depth definition: reach to a leaf node, where node.left == null && node.right == null
+- BFS using queue, track level.
+
+#### DFS
+- Divide and Conquer to find min depth.
+ - if one of child is null, return the other child depth + 1
+ - Pick the min of the two child depth + 1
+- need to visit all nodes
+
+
+```
+/*
+Given a binary tree, find its minimum depth.
+
+The minimum depth is the number of nodes along the shortest path
+from the root node down to the nearest leaf node.
+
+Example
+Given a binary tree as follow:
+
+ 1
+
+ / \
+
+ 2 3
+
+ / \
+
+ 4 5
+
+The minimum depth is 2
+
+Tags Expand
+Depth First Search
+*/
+
+/*
+BFS, 99.67%
+minimum depth, consider BFS, it reaches the termination point faster:
+if any node has null left/right child, that indicates the first leaf
+*/
+class Solution {
+ public int minDepth(TreeNode root) {
+ if (root == null) return 0;
+ Queue queue = new LinkedList<>();
+ queue.offer(root);
+ int level = 0;
+ while (!queue.isEmpty()) {
+ level++;
+ int size = queue.size();
+ for (int i = 0; i < size; i++) {
+ TreeNode node = queue.poll();
+ if (node.left == null && node.right == null) return level;
+ if (node.left != null) queue.offer(node.left);
+ if (node.right != null) queue.offer(node.right);
+ }
+ }
+ return level;
+ }
+}
+
+
+// DFS
+class Solution {
+ public int minDepth(TreeNode root) {
+ if (root == null) return 0;
+ if (root.left == null && root.right == null) return 1;
+
+ int leftDepth = minDepth(root.left);
+ int rightDepth = minDepth(root.right);
+
+ if (root.left == null || root.right == null) {
+ return (root.left == null ? rightDepth : leftDepth) + 1;
+ }
+
+ return Math.min(leftDepth, rightDepth) + 1;
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/1110. Delete Nodes And Return Forest.java b/Java/1110. Delete Nodes And Return Forest.java
new file mode 100755
index 0000000..874f767
--- /dev/null
+++ b/Java/1110. Delete Nodes And Return Forest.java
@@ -0,0 +1,151 @@
+M
+tags: Tree, DFS, Divide and Conquer
+time: O(n)
+space: O(logn)
+
+#### Method1: DFS, divide and conquer
+- dfs function: have toDelete set, and a result list
+- dive deep into child node FIRST, and test if a removal is needed at bottom of tree
+- if remove, add orphan and return null; otherwise, return itself
+- time: O(n), visit all nodes
+- space: O(logn), height of the tree
+
+#### Method2: HashMap, DFS.
+- traverse tree and create `map ` to fast O(1) removal. O(n)
+- set root into a rootSet
+- after deleting a node A, the children of the node becomes 2 forests root
+ - children should be marked in rootSet
+ - also remove node A from rootSet (if appears)
+- output: find all root in root set, traverse and output.
+- This approach requires a dfs build of parentMap
+ - it is same amount of efforts to do the regular dfs removal.
+ - not a good solution
+- time: O(n)
+- space: O(n)
+
+```
+
+/*
+Given the root of a binary tree, each node in the tree has a distinct value.
+
+After deleting all nodes with a value in to_delete, we are left with a forest (a disjoint union of trees).
+
+Return the roots of the trees in the remaining forest. You may return the result in any order.
+
+
+
+Example 1:
+
+
+
+Input: root = [1,2,3,4,5,6,7], to_delete = [3,5]
+Output: [[1,2,null,4],[6],[7]]
+
+
+Constraints:
+
+The number of nodes in the given tree is at most 1000.
+Each node has a distinct value between 1 and 1000.
+to_delete.length <= 1000
+to_delete contains distinct values between 1 and 1000.
+
+
+*/
+
+
+
+/*
+#### Method1: DFS, divide and conquer
+- dfs function: have toDelete set, and a result list
+- dive deep into child node FIRST, and test if a removal is needed at bottom of tree
+- if remove, add orphan and return null; otherwise, return itself
+*/
+class Solution {
+
+ public List delNodes(TreeNode root, int[] toDelete) {
+ Set toDeleteSet = new HashSet<>();
+ for (int val : toDelete) toDeleteSet.add(val);
+ List rst = new ArrayList<>();
+ root = dfs(root, toDeleteSet, rst);
+ if (root != null) rst.add(root);
+ return rst;
+ }
+
+ private TreeNode dfs(TreeNode node, Set toDeleteSet, List rst) {
+ if (node == null) return null;
+ node.left = dfs(node.left, toDeleteSet, rst);
+ node.right = dfs(node.right, toDeleteSet, rst);
+
+ if (toDeleteSet.contains(node.val)) {
+ if (node.left != null) rst.add(node.left);
+ if (node.right != null) rst.add(node.right);
+ return null;
+ }
+ return node;
+ }
+}
+
+
+/*
+#### Method2: HashMap, DFS
+- traverse tree and create `map ` to fast removal. O(n)
+- set root into a rootSet
+- after deleting a node A, the children of the node becomes 2 forests root
+ - children should be marked in rootSet
+ - also remove node A from rootSet (if appears)
+- output: find all root in root set, traverse and output.
+- time: O(n)
+- space: O(n)
+*/
+class Solution {
+
+ public List delNodes(TreeNode root, int[] toDelete) {
+
+ Map rootMap = new HashMap<>();
+ Map parentMap = new HashMap<>();
+ buildMap(parentMap, root);
+
+ rootMap.put(root.val, root);
+
+ for (int val : toDelete) {
+ TreeNode nodeToDelete;
+ if (rootMap.containsKey(val)) {
+ nodeToDelete = rootMap.get(val);
+ rootMap.remove(val);
+ } else {
+ nodeToDelete = remove(parentMap.get(val), val); // node = 3, 5
+ parentMap.remove(val);
+ }
+ if (nodeToDelete.left != null) rootMap.put(nodeToDelete.left.val, nodeToDelete.left); // add: 6, null
+ if (nodeToDelete.right != null) rootMap.put(nodeToDelete.right.val, nodeToDelete.right); // add: 7, null
+ }
+
+ return new ArrayList<>(rootMap.values());
+ }
+
+ private TreeNode remove(TreeNode parent, int val) {
+ TreeNode node;
+ if (parent.left != null && parent.left.val == val) {
+ node = parent.left;
+ parent.left = null;
+ } else {
+ node = parent.right;
+ parent.right = null;
+ }
+ return node;
+ }
+
+ private void buildMap(Map map, TreeNode node) {
+ if (node == null) return;
+ if (node.left != null) {
+ map.put(node.left.val, node);
+ buildMap(map, node.left);
+ }
+ if (node.right != null) {
+ map.put(node.right.val, node);
+ buildMap(map, node.right);
+ }
+ }
+}
+
+```
\ No newline at end of file
diff --git a/Java/1117. Building H2O.java b/Java/1117. Building H2O.java
new file mode 100755
index 0000000..353924d
--- /dev/null
+++ b/Java/1117. Building H2O.java
@@ -0,0 +1,115 @@
+M
+tags: Thread, Semaphore, Lock
+
+
+#### Meethod1: Use lock & counter to lock a thread based on counter
+- when counter != 2 , it will execute hydrogen() two times so that 'H' will reach 2
+- when count == 2, it will execute oxygen() once so that 'O' will reach 2
+
+#### Method2: use Semaphore to manage the life cycle of 'H' and 'O'
+- to start: H is at count 2 and O is at count 0. They need both be at 0 to be unlocked
+- hydrogen():
+ - `h.acquire()` will execute 2 times until H.count is reduced to 0
+ - `o.release` will add O.count by 1 for 2 times
+- oxygen():
+ - `o.acquire(2)` can only occur when O.count == 2 due to the 2 calls in `hydrogen(..)`
+ - `h.release(2)` will restore the H.count back to 2
+- semaphore: https://www.geeksforgeeks.org/semaphore-in-java/
+
+```
+/*
+There are two kinds of threads, oxygen and hydrogen. Your goal is to group these threads to form water molecules. There is a barrier where each thread has to wait until a complete molecule can be formed. Hydrogen and oxygen threads will be given releaseHydrogen and releaseOxygen methods respectively, which will allow them to pass the barrier. These threads should pass the barrier in groups of three, and they must be able to immediately bond with each other to form a water molecule. You must guarantee that all the threads from one molecule bond before any other threads from the next molecule do.
+
+In other words:
+
+If an oxygen thread arrives at the barrier when no hydrogen threads are present, it has to wait for two hydrogen threads.
+If a hydrogen thread arrives at the barrier when no other threads are present, it has to wait for an oxygen thread and another hydrogen thread.
+We don’t have to worry about matching the threads up explicitly; that is, the threads do not necessarily know which other threads they are paired up with. The key is just that threads pass the barrier in complete sets; thus, if we examine the sequence of threads that bond and divide them into groups of three, each group should contain one oxygen and two hydrogen threads.
+
+Write synchronization code for oxygen and hydrogen molecules that enforces these constraints.
+
+
+
+Example 1:
+
+Input: "HOH"
+Output: "HHO"
+Explanation: "HOH" and "OHH" are also valid answers.
+Example 2:
+
+Input: "OOHHHH"
+Output: "HHOHHO"
+Explanation: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" and "OHHOHH" are also valid answers.
+
+
+Constraints:
+
+Total length of input string will be 3n, where 1 ≤ n ≤ 20.
+Total number of H will be 2n in the input string.
+Total number of O will be n in the input string.
+*/
+
+/*
+Meethod1: Use lock & counter to lock a thread based on counter
+- when counter != 2 , it will execute hydrogen() two times so that 'H' will reach 2
+- when count == 2, it will execute oxygen() once so that 'O' will reach 2
+*/
+class H2O {
+ private Object lock = new Object();
+ private int count = 0;
+ public H2O() { }
+
+ public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
+ synchronized (lock) {
+ while(count==2) lock.wait();
+ releaseHydrogen.run();
+ count++;
+ lock.notifyAll();
+ }
+ }
+
+ public void oxygen(Runnable releaseOxygen) throws InterruptedException {
+ synchronized (lock) {
+ while(count!=2) lock.wait();
+ releaseOxygen.run();
+ count = 0;
+ lock.notifyAll();
+ }
+ }
+}
+
+/*
+Method2: use Semaphore to manage the life cycle of 'H' and 'O'
+- to start: H is at count 2 and O is at count 0. They need both be at 0 to be unlocked
+- hydrogen():
+ - `h.acquire()` will execute 2 times until H.count is reduced to 0
+ - `o.release` will add O.count by 1 for 2 times
+- oxygen():
+ - `o.acquire(2)` can only occur when O.count == 2 due to the 2 calls in `hydrogen(..)`
+ - `h.release(2)` will restore the H.count back to 2
+*/
+class H2O {
+ Semaphore h, o;
+ public H2O() {
+ h = new Semaphore(2, true);
+ o = new Semaphore(0, true);
+ }
+
+ public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
+ h.acquire();
+ // releaseHydrogen.run() outputs "H". Do not change or remove this line.
+ releaseHydrogen.run();
+ o.release();
+ }
+
+ public void oxygen(Runnable releaseOxygen) throws InterruptedException {
+ o.acquire(2);
+ // releaseOxygen.run() outputs "O". Do not change or remove this line.
+ releaseOxygen.run();
+ h.release(2);
+ }
+}
+
+
+
+```
\ No newline at end of file
diff --git a/Java/112. Path Sum.java b/Java/112. Path Sum.java
new file mode 100755
index 0000000..da6bc35
--- /dev/null
+++ b/Java/112. Path Sum.java
@@ -0,0 +1,56 @@
+E
+tags: Tree, DFS
+
+给一个inputSum, 然后dfs, 找到是否有一条path, 得出的path sum 跟 inputSum 一样.
+
+#### DFS
+- 确定好结尾条件: `is leaf` && `val == sum`.
+- 每一层减掉node.val, 然后dfs.
+- 写一写: `root == null => false` 对parent nodes的影响. 这里发现没影响, 所以可以简化成用1个functionDFS.
+
+
+```
+/*
+Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
+
+Note: A leaf is a node with no children.
+
+Example:
+
+Given the below binary tree and sum = 22,
+
+ 5
+ / \
+ 4 8
+ / / \
+ 11 13 4
+ / \ \
+7 2 1
+return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
+*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+/*
+Thoughts:
+DFS on the function itself, keep subtracting the root.val.
+when root == null && sum == 0, return true;
+*/
+
+class Solution {
+ public boolean hasPathSum(TreeNode root, int sum) {
+ if (root == null) return false;
+ if (root.left == null && root.right == null && sum == root.val) return true;
+ return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
+ }
+}
+
+
+```
\ No newline at end of file
diff --git a/Java/1123. Lowest Common Ancestor of Deepest Leaves.java b/Java/1123. Lowest Common Ancestor of Deepest Leaves.java
new file mode 100755
index 0000000..ff12a8b
--- /dev/null
+++ b/Java/1123. Lowest Common Ancestor of Deepest Leaves.java
@@ -0,0 +1,142 @@
+M
+tags: DFS, Tree, BFS
+time: O(n)
+space: O(n)
+
+#### Method1: DFS, top-down
+- key concetpL the `common ancester of deppest leaves` must have its `two branch being same depth`. problem sovled.
+- dfs on both branch
+- if returned depth equals & equal to max depth, record common ancestor
+- time: O(n) traversal 1 pass
+- space: O(n) dfs worst case depth
+
+#### Method2: bottom-up, find leaves first and traverse backwards
+- 1) find leaf nodes, and store backward map to root (DFS/ BFS both work)
+- 2) use leaf nodes to find way backwards till common node is found; return
+- time: O(n) but two passes
+- space: O(n) dsf + map storage
+- this approach is more brutle and uses exrtra spaces
+
+```
+
+/*
+Given a rooted binary tree, return the lowest common ancestor of its deepest leaves.
+
+Recall that:
+
+The node of a binary tree is a leaf if and only if it has no children
+The depth of the root of the tree is 0, and if the depth of a node is d, the depth of each of its children is d+1.
+The lowest common ancestor of a set S of nodes is the node A with the largest depth such that every node in S is in the subtree with root A.
+
+
+Example 1:
+
+Input: root = [1,2,3]
+Output: [1,2,3]
+Explanation:
+The deepest leaves are the nodes with values 2 and 3.
+The lowest common ancestor of these leaves is the node with value 1.
+The answer returned is a TreeNode object (not an array) with serialization "[1,2,3]".
+Example 2:
+
+Input: root = [1,2,3,4]
+Output: [4]
+Example 3:
+
+Input: root = [1,2,3,4,5]
+Output: [2,4,5]
+
+
+Constraints:
+
+The given tree will have between 1 and 1000 nodes.
+Each node of the tree will have a distinct value between 1 and 1000.
+*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+/*
+Method1: the common ancester of deppest leaves must have its two branch being same depth. problem sovled.
+- dfs on both branch
+- if returned depth equals & equal to max depth, record common ancestor
+*/
+class Solution {
+ TreeNode lca;
+ int max = 0;
+ public TreeNode lcaDeepestLeaves(TreeNode root) {
+ if (root == null) return root;
+ dfs(root, 0);
+ return lca;
+ }
+
+ private int dfs(TreeNode node, int depth) {
+ if (node == null) {
+ max = Math.max(max, depth);
+ return depth;
+ }
+
+ int leftDepth = dfs(node.left, depth + 1);
+ int rightDepth = dfs(node.right, depth + 1);
+
+ if (leftDepth == max && rightDepth == max) {
+ lca = node;
+ }
+ return Math.max(leftDepth, rightDepth);
+ }
+}
+
+
+/*
+Method2:
+1) find leaf nodes, and store backward map to root (DFS/ BFS both work)
+2) use leaf nodes to find way backwards till common node is found; return
+*/
+class Solution {
+ Map parentMap = new HashMap<>();
+ Map> depthMap = new HashMap<>();
+ int max = 0;
+ public TreeNode lcaDeepestLeaves(TreeNode root) {
+ if (root == null) return root;
+ dfs(root, 0);
+ Queue queue = depthMap.get(max); // leaves
+ if (queue.size() == 1) return queue.poll();
+
+ while (!queue.isEmpty()) {
+ int size = queue.size();
+ Set set = new HashSet<>();
+ while (size-- > 0) {
+ TreeNode node = queue.poll();
+ set.add(parentMap.get(node));
+ }
+ if (set.size() == 1) return set.iterator().next();
+ queue.addAll(set);
+ }
+
+ return root;
+ }
+
+ private void dfs(TreeNode node, int depth) {
+ if (node.left == null && node.right == null) {
+ max = Math.max(max, depth);
+ depthMap.putIfAbsent(depth, new LinkedList<>());
+ depthMap.get(depth).offer(node);
+ return;
+ }
+ if (node.left != null) {
+ parentMap.put(node.left, node);
+ dfs(node.left, depth + 1);
+ }
+ if (node.right != null) {
+ parentMap.put(node.right, node);
+ dfs(node.right, depth + 1);
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/Java/114. Flatten Binary Tree to Linked List.java b/Java/114. Flatten Binary Tree to Linked List.java
new file mode 100755
index 0000000..b24946b
--- /dev/null
+++ b/Java/114. Flatten Binary Tree to Linked List.java
@@ -0,0 +1,156 @@
+M
+tags: Binary Tree, DFS
+time: O(n)
+space: O(n), stacks
+
+给一个binary tree, 把tree做成 linked list的形式, in-place.
+
+#### Method1: DFS return tail node
+- DFS to return the tail of the flattened list
+- Careful handling the null child. Choose one and both works:
+ - Option1: put non-null as right child and continue dfs
+ - Option2: put non-null as left child and continue dfs
+
+#### Method2: void DFS
+- latten the tree, no extra space.
+ - 1. Set right node in buffer, and connect: `root.right = root.left`, DFS flatten(root.right)
+ - 3. 移花接木: traverse to tail of the current root.right and attach the buffer node.
+ - 3. flatten the remaining of buffer
+
+##### 注意
+- 顺序一定要清楚, 不能写错, 写几个example可以看出来
+- 移动的那些node, 要把node.left = null, 清扫干净
+
+```
+/*
+Given a binary tree, flatten it to a linked list in-place.
+
+For example,
+Given
+
+ 1
+ / \
+ 2 5
+ / \ \
+ 3 4 6
+The flattened tree should look like:
+ 1
+ \
+ 2
+ \
+ 3
+ \
+ 4
+ \
+ 5
+ \
+ 6
+click to show hints.
+
+Hints:
+If you notice carefully in the flattened tree, each node's right child points to
+the next node of a pre-order traversal.
+
+Challenge
+Do it in-place without any extra memory.
+
+*/
+
+/**
+ * Definition for a binary tree node.
+ * public class TreeNode {
+ * int val;
+ * TreeNode left;
+ * TreeNode right;
+ * TreeNode(int x) { val = x; }
+ * }
+ */
+// Method1, Option1: DFS by returning and attaching tail, move non-null child to right side
+class Solution {
+ public void flatten(TreeNode root) {
+ if (root == null) return;
+ dfs(root);
+ }
+
+ public TreeNode dfs(TreeNode node) {
+ if (node.left == null && node.right == null) return node;
+ if (node.right == null) { // when one of them is null, attach remaining to right side
+ node.right = node.left;
+ node.left = null;
+ }
+ TreeNode temp = node.right; // buffer
+
+ if (node.left != null) { // DFS to find tail, and attach right to tail
+ TreeNode tail = dfs(node.left);
+ node.right = node.left;
+ node.left = null;
+ tail.right = temp;
+ }
+
+ // DFS the rest right
+ return dfs(temp);
+ }
+}
+
+// Method1, Option2: DFS by returning and attaching tail, move non-null child to left
+class Solution {
+ public void flatten(TreeNode root) {
+ if (root == null) return;
+ dfs(root);
+ }
+
+ public TreeNode dfs(TreeNode node) {
+ if (node.left == null && node.right == null) return node;
+ if (node.left == null) { // node.right != null, then swich right to left, so the logic below can work
+ node.left = node.right;
+ node.right = null;
+ }
+
+ TreeNode temp = node.right;
+
+ TreeNode tail = dfs(node.left);
+ node.right = node.left;
+ node.left = null;
+
+ if (temp == null) return tail; // do not test null right
+
+ tail.right = temp;
+ return dfs(temp);
+ }
+}
+
+/*
+Method2:
+1. Move root.left to root.rigthMost child (while loop find leaf)
+2. Take notion of the first root.right, and flatten(xx) on it.
+3. On each level, if not left child, flatten right child.
+*/
+class Solution {
+ public void flatten(TreeNode root) {
+ if (root == null) return;
+ if (root.left == null) {
+ flatten(root.right);
+ } else {
+ // Reserve right sub tree
+ TreeNode rightNode = root.right;
+
+ // Move left child to right side, cut off original left child
+ root.right = root.left;
+ root.left = null;
+
+ // Flatten the new right child
+ flatten(root.right);
+
+ // Append previous right child to end of flatten tree
+ TreeNode node = root;
+ while (node.right != null) {
+ node = node.right;
+ }
+ node.right = rightNode; // connect
+ flatten(root.right);
+ }
+ }
+}
+
+
+```
\ No newline at end of file
diff --git a/Java/1146. Snapshot Array.java b/Java/1146. Snapshot Array.java
new file mode 100755
index 0000000..04fced3
--- /dev/null
+++ b/Java/1146. Snapshot Array.java
@@ -0,0 +1,89 @@
+M
+tags: Array, Hash Table, TreeMap
+time: O(1) set, O(logn) get, O(x) snap, x = # of changes
+space: O(n * m), n = array size, m = # of snaps
+
+
+#### Hash Table, TreeMap; atomic save
+- store efficiently: use List