diff --git a/README.md b/README.md
index 37d9a0f..a008d61 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# LeetCode-Java
## 说明
-- leetcode练习,坚持每天一道,目前已完成233道
+- leetcode练习,坚持每天一道,目前已完成275道
- 解题语言是Java
- 每道题都是可编译运行的
- 每道题有自己的方法和他人优秀解法
@@ -10,21 +10,19 @@
- 网址:https://leetcode-cn.com/
## 待解题目列表
-扫题:顺序
+剑指offer系列-持续多周,每周7题
-- [x] [83. 删除排序链表中的重复元素](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/leetcode/_83_deleteDuplicates.java)
+- [x] [剑指 Offer 16. 数值的整数次方](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/offer/_16_myPow.java)
+- [x] [剑指 Offer 17. 打印从1到最大的n位数](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/offer/_17_printNumbers.java)
+- [x] [剑指 Offer 18. 删除链表的节点](https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/)
+- [ ] [剑指 Offer 19. 正则表达式匹配](https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof/)
+- [ ] [剑指 Offer 20. 表示数值的字符串](https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/)
+- [ ] [剑指 Offer 21. 调整数组顺序使奇数位于偶数前面](https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/)
+- [ ] [剑指 Offer 22. 链表中倒数第k个节点](https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
-- [x] [87. 扰乱字符串](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/leetcode/_87_isScramble.java)
-
-- [x] [88. 合并两个有序数组](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/leetcode/_88_merge.java)
-
-- [ ] [89. 格雷编码](https://leetcode-cn.com/problems/gray-code/)
-
-- [ ] [97. 交错字符串](https://leetcode-cn.com/problems/interleaving-string/)
-
-- [ ] [99. 恢复二叉搜索树](https://leetcode-cn.com/problems/recover-binary-search-tree/)
+LCP
-- [ ] [100. 相同的树](https://leetcode-cn.com/problems/same-tree/)
+- [x] [LCP 06. 拿硬币](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/LCP/_6_minCount.java)
## 已解题目
@@ -59,9 +57,32 @@
- [线段树](https://leetcode-cn.com/tag/segment-tree/)(9)
- [二叉搜索树](https://leetcode-cn.com/tag/binary-search-tree/)(15)
-### 题目列表(更新中—已完成233)
+### 题目列表(更新中—已完成275)
-[Leetcode-Java(200+题解,持续更新、欢迎star&留言&交流)](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/leetcode/_88_merge.java)
+[Leetcode-Java(270+题解,持续更新、欢迎star&留言&交流)](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/offer/_18_deleteNode.java)
+
+#### 剑指offer系列
+
+| 题目 | 解决方案 | 相关话题 | 难度 | 备注 |
+| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------ | ---- |
+| [剑指 Offer 03. 数组中重复的数字](https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/) | [FindRepeatNumber](https://github.com/pphdsny/Leetcode-Java/blob/master/src/pp/arithmetic/offer/_03_findRepeatNumber.java) | [数组](
+ * 桌上有 n 堆力扣币,每堆的数量保存在数组 coins 中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。 + *
+ * 示例 1: + *
+ * 输入:[4,2,1] + *
+ * 输出:4 + *
+ * 解释:第一堆力扣币最少需要拿 2 次,第二堆最少需要拿 1 次,第三堆最少需要拿 1 次,总共 4 次即可拿完。 + *
+ * 示例 2: + *
+ * 输入:[2,3,10] + *
+ * 输出:8 + *
+ * 限制: + *
+ * 1 <= n <= 4 + * 1 <= coins[i] <= 10 + *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/na-ying-bi
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _6_minCount {
+
+ public static void main(String[] args) {
+ _6_minCount minCount = new _6_minCount();
+ System.out.println(minCount.minCount(new int[]{4, 2, 1}));
+ System.out.println(minCount.minCount(new int[]{2, 3, 10}));
+
+ }
+
+ /**
+ * 解题思路:
+ * 需要最少次数,利用贪心的思路,每次尽可能的多拿(也就是2个)
+ *
+ * @param coins
+ * @return
+ */
+ public int minCount(int[] coins) {
+ if (coins == null) return 0;
+ int retVal = 0;
+ for (int i = 0; i < coins.length; i++) {
+ int coin = coins[i];
+ if (coin % 2 == 0) {
+ retVal += coin / 2;
+ } else {
+ retVal += coin / 2 + 1;
+ }
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/pp/arithmetic/Util.java b/src/pp/arithmetic/Util.java
index 4db874e..7e38661 100644
--- a/src/pp/arithmetic/Util.java
+++ b/src/pp/arithmetic/Util.java
@@ -4,7 +4,9 @@
import pp.arithmetic.model.ListNode;
import pp.arithmetic.model.TreeNode;
+import java.util.ArrayDeque;
import java.util.List;
+import java.util.Queue;
import java.util.Random;
/**
@@ -102,6 +104,35 @@ public static TreeNode generateTreeNode() {
return root;
}
+ public static TreeNode generateTreeNode(Integer[] nodes) {
+ if (nodes == null || nodes.length == 0 || nodes[0] == null) return null;
+ TreeNode root = new TreeNode(nodes[0]);
+ Queue
+ * 我们提供了一个类:
+ *
+ * public class Foo {
+ * public void one() { print("one"); }
+ * public void two() { print("two"); }
+ * public void three() { print("three"); }
+ * }
+ * 三个不同的线程将会共用一个 Foo 实例。
+ *
+ * 线程 A 将会调用 one() 方法
+ * 线程 B 将会调用 two() 方法
+ * 线程 C 将会调用 three() 方法
+ * 请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。
+ *
+ *
+ *
+ * 示例 1:
+ *
+ * 输入: [1,2,3]
+ * 输出: "onetwothree"
+ * 解释:
+ * 有三个线程会被异步启动。
+ * 输入 [1,2,3] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 two() 方法,线程 C 将会调用 three() 方法。
+ * 正确的输出是 "onetwothree"。
+ * 示例 2:
+ *
+ * 输入: [1,3,2]
+ * 输出: "onetwothree"
+ * 解释:
+ * 输入 [1,3,2] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 three() 方法,线程 C 将会调用 two() 方法。
+ * 正确的输出是 "onetwothree"。
+ *
+ *
+ * 注意:
+ *
+ * 尽管输入中的数字似乎暗示了顺序,但是我们并不保证线程在操作系统中的调度顺序。
+ *
+ * 你看到的输入格式主要是为了确保测试的全面性。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/print-in-order
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _1114_Foo {
+
+ public static void main(String[] args) {
+ Foo foo = new Foo();
+ Runnable runnable1 = new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("printFirst");
+ }
+ };
+ Runnable runnable2 = new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("printSecond");
+ }
+ };
+ Runnable runnable3 = new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("printThird");
+ }
+ };
+ try {
+ foo.first(runnable1);
+ foo.third(runnable3);
+ foo.second(runnable2);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ //一道题自己没有跑成功,不知道测试用例如何输出的
+ static class Foo {
+
+ private AtomicInteger firstJobDone = new AtomicInteger(0);
+ private AtomicInteger secondJobDone = new AtomicInteger(0);
+
+ public Foo() {}
+
+ public void first(Runnable printFirst) throws InterruptedException {
+ // printFirst.run() outputs "first".
+ printFirst.run();
+ // mark the first job as done, by increasing its count.
+ firstJobDone.incrementAndGet();
+ }
+
+ public void second(Runnable printSecond) throws InterruptedException {
+ while (firstJobDone.get() != 1) {
+ // waiting for the first job to be done.
+ }
+ // printSecond.run() outputs "second".
+ printSecond.run();
+ // mark the second as done, by increasing its count.
+ secondJobDone.incrementAndGet();
+ }
+
+ public void third(Runnable printThird) throws InterruptedException {
+ while (secondJobDone.get() != 1) {
+ // waiting for the second job to be done.
+ }
+ // printThird.run() outputs "third".
+ printThird.run();
+ }
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_1115_FooBar.java b/src/pp/arithmetic/leetcode/_1115_FooBar.java
new file mode 100644
index 0000000..b981d43
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_1115_FooBar.java
@@ -0,0 +1,111 @@
+package pp.arithmetic.leetcode;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * Created by wangpeng on 2020-07-08.
+ * 1115. 交替打印FooBar
+ *
+ * 我们提供一个类:
+ *
+ * class FooBar {
+ * public void foo() {
+ * for (int i = 0; i < n; i++) {
+ * print("foo");
+ * }
+ * }
+ *
+ * public void bar() {
+ * for (int i = 0; i < n; i++) {
+ * print("bar");
+ * }
+ * }
+ * }
+ * 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
+ *
+ * 请设计修改程序,以确保 "foobar" 被输出 n 次。
+ *
+ *
+ *
+ * 示例 1:
+ *
+ * 输入: n = 1
+ * 输出: "foobar"
+ * 解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。
+ * 示例 2:
+ *
+ * 输入: n = 2
+ * 输出: "foobarfoobar"
+ * 解释: "foobar" 将被输出两次。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/print-foobar-alternately
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _1115_FooBar {
+
+ public static void main(String[] args) {
+
+ FooBar fooBar = new FooBar(5);
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ fooBar.foo(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("foo");
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ fooBar.bar(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("bar");
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+
+ }
+
+ static class FooBar {
+ private Semaphore fooSe = new Semaphore(0);
+ private Semaphore barSe = new Semaphore(1);
+
+ private int n;
+
+ public FooBar(int n) {
+ this.n = n;
+ }
+
+ public void foo(Runnable printFoo) throws InterruptedException {
+
+ for (int i = 0; i < n; i++) {
+ barSe.acquire();
+ printFoo.run();
+ fooSe.release();
+ }
+ }
+
+ public void bar(Runnable printBar) throws InterruptedException {
+
+ for (int i = 0; i < n; i++) {
+ fooSe.acquire();
+ printBar.run();
+ barSe.release();
+ }
+ }
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_1116_ZeroEvenOdd.java b/src/pp/arithmetic/leetcode/_1116_ZeroEvenOdd.java
new file mode 100644
index 0000000..5aeac21
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_1116_ZeroEvenOdd.java
@@ -0,0 +1,125 @@
+package pp.arithmetic.leetcode;
+
+import java.util.concurrent.Semaphore;
+import java.util.function.IntConsumer;
+
+/**
+ * Created by wangpeng on 2020-07-09.
+ * 1116. 打印零与奇偶数
+ *
+ * 假设有这么一个类:
+ *
+ * class ZeroEvenOdd {
+ * public ZeroEvenOdd(int n) { ... } // 构造函数
+ * public void zero(printNumber) { ... } // 仅打印出 0
+ * public void even(printNumber) { ... } // 仅打印出 偶数
+ * public void odd(printNumber) { ... } // 仅打印出 奇数
+ * }
+ * 相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程:
+ *
+ * 线程 A 将调用 zero(),它只输出 0 。
+ * 线程 B 将调用 even(),它只输出偶数。
+ * 线程 C 将调用 odd(),它只输出奇数。
+ * 每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506... ,其中序列的长度必须为 2n。
+ *
+ *
+ *
+ * 示例 1:
+ *
+ * 输入:n = 2
+ * 输出:"0102"
+ * 说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),最后一个线程调用odd()。正确的输出为 "0102"。
+ * 示例 2:
+ *
+ * 输入:n = 5
+ * 输出:"0102030405"
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/print-zero-even-odd
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _1116_ZeroEvenOdd {
+
+ public static void main(String[] args) {
+ ZeroEvenOdd zeroEvenOdd = new ZeroEvenOdd(5);
+ IntConsumer printNumber = new IntConsumer() {
+ @Override
+ public void accept(int value) {
+ System.out.println(value);
+ }
+ };
+ new Thread(){
+ @Override
+ public void run() {
+ super.run();
+ try {
+ zeroEvenOdd.zero(printNumber);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ new Thread(){
+ @Override
+ public void run() {
+ super.run();
+ try {
+ zeroEvenOdd.even(printNumber);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ new Thread(){
+ @Override
+ public void run() {
+ super.run();
+ try {
+ zeroEvenOdd.odd(printNumber);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
+
+ static class ZeroEvenOdd {
+ private int n;
+ private Semaphore zeroSe = new Semaphore(1);
+ private Semaphore evenSe = new Semaphore(0);
+ private Semaphore oddSe = new Semaphore(0);
+
+ public ZeroEvenOdd(int n) {
+ this.n = n;
+ }
+
+ // printNumber.accept(x) outputs "x", where x is an integer.
+ public void zero(IntConsumer printNumber) throws InterruptedException {
+ for (int i = 0; i < n; i++) {
+ zeroSe.acquire();
+ printNumber.accept(0);
+ if (i % 2 == 0) {
+ evenSe.release();
+ } else {
+ oddSe.release();
+ }
+ }
+ }
+
+ public void even(IntConsumer printNumber) throws InterruptedException {
+ for (int i = 1; i <= n; i+=2) {
+ evenSe.acquire();
+ printNumber.accept(i);
+ zeroSe.release();
+ }
+ }
+
+ public void odd(IntConsumer printNumber) throws InterruptedException {
+ for (int i = 2; i <= n; i+=2) {
+ oddSe.acquire();
+ printNumber.accept(i);
+ zeroSe.release();
+ }
+ }
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_1117_H2O.java b/src/pp/arithmetic/leetcode/_1117_H2O.java
new file mode 100644
index 0000000..79a195e
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_1117_H2O.java
@@ -0,0 +1,197 @@
+package pp.arithmetic.leetcode;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.Semaphore;
+
+/**
+ * Created by wangpeng on 2020-07-15.
+ * 1117. H2O 生成
+ *
+ * 现在有两种线程,氧 oxygen 和氢 hydrogen,你的目标是组织这两种线程来产生水分子。
+ *
+ * 存在一个屏障(barrier)使得每个线程必须等候直到一个完整水分子能够被产生出来。
+ *
+ * 氢和氧线程会被分别给予 releaseHydrogen 和 releaseOxygen 方法来允许它们突破屏障。
+ *
+ * 这些线程应该三三成组突破屏障并能立即组合产生一个水分子。
+ *
+ * 你必须保证产生一个水分子所需线程的结合必须发生在下一个水分子产生之前。
+ *
+ * 换句话说:
+ *
+ * 如果一个氧线程到达屏障时没有氢线程到达,它必须等候直到两个氢线程到达。
+ * 如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
+ * 书写满足这些限制条件的氢、氧线程同步代码。
+ *
+ *
+ *
+ * 示例 1:
+ *
+ * 输入: "HOH"
+ * 输出: "HHO"
+ * 解释: "HOH" 和 "OHH" 依然都是有效解。
+ * 示例 2:
+ *
+ * 输入: "OOHHHH"
+ * 输出: "HHOHHO"
+ * 解释: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" 和 "OHHOHH" 依然都是有效解。
+ *
+ *
+ * 提示:
+ *
+ * 输入字符串的总长将会是 3n, 1 ≤ n ≤ 50;
+ * 输入字符串中的 “H” 总数将会是 2n 。
+ * 输入字符串中的 “O” 总数将会是 n 。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/building-h2o
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _1117_H2O {
+
+
+ public static void main(String[] args) {
+
+ int n = 6;
+ H2O h2O = new H2O();
+ for (int i = 0; i < n * 2; i++) {
+ //H
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ try {
+ h2O.hydrogen(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("H");
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
+ for (int i = 0; i < n; i++) {
+ //O
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ try {
+ h2O.oxygen(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("O");
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
+ }
+
+ //使用系统类进行优化
+ class H2O2 {
+
+ private Semaphore hs;
+ private Semaphore os;
+ private CyclicBarrier totalBarrier;
+
+ public H2O2() {
+ hs = new Semaphore(2);
+ os = new Semaphore(1);
+ //await用于标识等待所有的线程都达到barrier才继续执行
+ totalBarrier = new CyclicBarrier(3);
+ }
+
+ public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
+ hs.acquire();
+ // releaseHydrogen.run() outputs "H". Do not change or remove this line.
+ releaseHydrogen.run();
+ try {
+ totalBarrier.await();
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+ hs.release();
+ }
+
+ public void oxygen(Runnable releaseOxygen) throws InterruptedException {
+ os.acquire();
+ // releaseOxygen.run() outputs "O". Do not change or remove this line.
+ releaseOxygen.run();
+ try {
+ totalBarrier.await();
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+ os.release();
+ }
+ }
+
+
+ static class H2O {
+
+ private final Object lock = new Object();
+ private int hc = 2;
+ private int oc = 1;
+
+ public H2O() {
+
+ }
+
+ public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
+
+ boolean flag = false;
+ synchronized (lock) {
+ while (hc == 0) {
+ lock.wait();
+ synchronized (lock) {
+ if (hc > 0) {
+ hc--;
+ flag = true;
+ break;
+ }
+ }
+ }
+ if (!flag) hc--;
+ // releaseHydrogen.run() outputs "H". Do not change or remove this line.
+ releaseHydrogen.run();
+ reset();
+ }
+ }
+
+ public void oxygen(Runnable releaseOxygen) throws InterruptedException {
+ boolean flag = false;
+ synchronized (lock) {
+ while (oc == 0) {
+ lock.wait();
+ synchronized (lock) {
+ if (oc > 0) {
+ oc--;
+ flag = true;
+ break;
+ }
+ }
+ }
+ if (!flag) oc--;
+ // releaseOxygen.run() outputs "O". Do not change or remove this line.
+ releaseOxygen.run();
+ reset();
+ }
+ }
+
+ private void reset() {
+ if (hc == 0 && oc == 0) {
+ hc = 2;
+ oc = 1;
+ lock.notifyAll();
+ }
+ }
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_111_minDepth.java b/src/pp/arithmetic/leetcode/_111_minDepth.java
new file mode 100644
index 0000000..b294a1e
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_111_minDepth.java
@@ -0,0 +1,55 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.Util;
+import pp.arithmetic.model.TreeNode;
+
+/**
+ * Created by wangpeng on 2019-12-12.
+ * 111. 二叉树的最小深度
+ *
+ * 给定一个二叉树,找出其最小深度。
+ *
+ * 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
+ *
+ * 说明: 叶子节点是指没有子节点的节点。
+ *
+ * 示例:
+ *
+ * 给定二叉树 [3,9,20,null,null,15,7],
+ *
+ * 3
+ * / \
+ * 9 20
+ * / \
+ * 15 7
+ * 返回它的最小深度 2.
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _111_minDepth {
+
+ public static void main(String[] args) {
+ _111_minDepth minDepth = new _111_minDepth();
+ System.out.println(minDepth.minDepth(Util.generateTreeNode(new Integer[]{3, 9, 20, null, null, 15, 7})));
+ }
+
+ /**
+ * 解题思路:DFS求解
+ * 1、求左子树的最小深度
+ * 2、求右子树的最小深度
+ * 3、求根节点的最小深度 = Math.min(left,right)+1
+ *
+ * 需要注意一点:如左/右子树为空,得取有值得叶节点长度
+ *
+ * @param root
+ * @return
+ */
+ public int minDepth(TreeNode root) {
+ if (root == null) return 0;
+ int left = minDepth(root.left);
+ int right = minDepth(root.right);
+ return (left == 0 || right == 0) ? left + right + 1 : Math.min(left, right) + 1;
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_112_hasPathSum.java b/src/pp/arithmetic/leetcode/_112_hasPathSum.java
new file mode 100644
index 0000000..cc37d2e
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_112_hasPathSum.java
@@ -0,0 +1,67 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.Util;
+import pp.arithmetic.model.TreeNode;
+
+/**
+ * Created by wangpeng on 2019-12-12.
+ * 112. 路径总和
+ *
+ * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
+ *
+ * 说明: 叶子节点是指没有子节点的节点。
+ *
+ * 示例:
+ * 给定如下二叉树,以及目标和 sum = 22,
+ *
+ * 5
+ * / \
+ * 4 8
+ * / / \
+ * 11 13 4
+ * / \ \
+ * 7 2 1
+ * 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/path-sum
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _112_hasPathSum {
+
+ public static void main(String[] args) {
+ _112_hasPathSum hasPathSum = new _112_hasPathSum();
+ TreeNode treeNode = Util.generateTreeNode(new Integer[]{5, 4, 7, 11, null, 13, 4, 7, 2, null, null, null, 1});
+ System.out.println(hasPathSum.hasPathSum(treeNode,22));
+ System.out.println(hasPathSum.hasPathSum(Util.generateTreeNode(new Integer[]{1,2}),1));
+ }
+
+ /**
+ * 解题思路:
+ * 1、sum减去当前根节点的val,将新的sum传递给左右子树
+ * 2、左右子树重复步骤1
+ * 3、如最终的节点==null并且sum==0则找到目标路径
+ *
+ * 注意:叶节点的定义
+ *
+ * @param root
+ * @param sum
+ * @return
+ */
+ public boolean hasPathSum(TreeNode root, int sum) {
+ if (root == null) return false;
+ return dfs(root, sum);
+ }
+
+ private boolean dfs(TreeNode root, int sum) {
+ if (root == null) return sum == 0;
+ int newSum = sum - root.val;
+ if (root.left == null && root.right == null) return newSum == 0;
+ boolean left = dfs(root.left, newSum);
+ boolean right = dfs(root.right, newSum);
+ if (root.left != null && root.right != null) return left || right;
+ if (root.left != null) return left;
+ if (root.right != null) return right;
+ return false;
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_115_numDistinct.java b/src/pp/arithmetic/leetcode/_115_numDistinct.java
new file mode 100644
index 0000000..1610c0b
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_115_numDistinct.java
@@ -0,0 +1,142 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.Util;
+
+/**
+ * Created by wangpeng on 2019-12-13.
+ * 115. 不同的子序列
+ *
+ * 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
+ *
+ * 一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)
+ *
+ * 示例 1:
+ *
+ * 输入: S = "rabbbit", T = "rabbit"
+ * 输出: 3
+ * 解释:
+ *
+ * 如下图所示, 有 3 种可以从 S 中得到 "rabbit" 的方案。
+ * (上箭头符号 ^ 表示选取的字母)
+ *
+ * rabbbit
+ * ^^^^ ^^
+ * rabbbit
+ * ^^ ^^^^
+ * rabbbit
+ * ^^^ ^^^
+ * 示例 2:
+ *
+ * 输入: S = "babgbag", T = "bag"
+ * 输出: 5
+ * 解释:
+ *
+ * 如下图所示, 有 5 种可以从 S 中得到 "bag" 的方案。
+ * (上箭头符号 ^ 表示选取的字母)
+ *
+ * babgbag
+ * ^^ ^
+ * babgbag
+ * ^^ ^
+ * babgbag
+ * ^ ^^
+ * babgbag
+ * ^ ^^
+ * babgbag
+ * ^^^
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/distinct-subsequences
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _115_numDistinct {
+
+ public static void main(String[] args) {
+ _115_numDistinct numDistinct = new _115_numDistinct();
+ System.out.println(numDistinct.numDistinct("aaa", "aa"));
+ System.out.println(numDistinct.numDistinct("rabbbit", "rabbit"));
+ System.out.println(numDistinct.numDistinct("babgbag", "bag"));
+ System.out.println(numDistinct.numDistinct("adbdadeecadeadeccaeaabdabdbcdabddddabcaaadbabaaedeeddeaeebcdeabcaaaeeaeeabcddcebddebeebedaecccbdcbcedbdaeaedcdebeecdaaedaacadbdccabddaddacdddc", "bcddceeeebecbc"));
+ Util.printDivideLine();
+ System.out.println(numDistinct.numDistinct2("babgbag", "bag"));
+ System.out.println(numDistinct.numDistinct2("aaa", "aa"));
+ System.out.println(numDistinct.numDistinct2("rabbbit", "rabbit"));
+ System.out.println(numDistinct.numDistinct2("adbdadeecadeadeccaeaabdabdbcdabddddabcaaadbabaaedeeddeaeebcdeabcaaaeeaeeabcddcebddebeebedaecccbdcbcedbdaeaedcdebeecdaaedaacadbdccabddaddacdddc", "bcddceeeebecbc"));
+ }
+
+ /**
+ * 解题思路:
+ * 通过模拟题意中的过程,感知有点回溯的感觉:
+ * 1、优先匹配前面的
+ * 2、匹配上了之后,再匹配后面的
+ * 3、直到匹配到最后一个,向后搜索匹配的,直到末尾
+ * 4、最后一位匹配到末尾之后,倒数第二位向后搜索匹配
+ * 5、如此循环,直至第一位也匹配到末尾结束
+ *
+ * 可解题,遇到复杂的提交超时:
+ * 比如这跟case:
+ * "adbdadeecadeadeccaeaabdabdbcdabddddabcaaadbabaaedeeddeaeebcdeabcaaaeeaeeabcddcebddebeebedaecccbdcbcedbdaeaedcdebeecdaaedaacadbdccabddaddacdddc"
+ * "bcddceeeebecbc"
+ * 本地跑出结果:700531452
+ *
+ * 优化思考:是不是可以考虑将遍历过程中的一些结果保存起来,而不是每次凑重新计算==>动态规划{@link _115_numDistinct#numDistinct2(String, String)}
+ *
+ * @param s
+ * @param t
+ * @return
+ */
+ public int numDistinct(String s, String t) {
+ if (s.length() < t.length()) return 0;
+ int sum = 0;
+ int ti = 0;
+ int si = 0;
+ while (si < s.length() && ti < t.length()) {
+ if (s.charAt(si) == t.charAt(ti)) {
+ if (si + 1 < s.length() && ti + 1 < t.length()) {
+ sum += numDistinct(s.substring(si + 1), t.substring(ti + 1));
+ } else {
+ if (ti == t.length() - 1) {
+ sum += 1;
+ }
+ }
+ }
+ si++;
+ }
+
+ return sum;
+ }
+
+ /**
+ * 优化求解:找递进规律(s:babgbag,t:bag)
+ * T/S "" b a b g b a g
+ * "" 1 1 1 1 1 1 1 1
+ * b 0 1 1 2 2 3 3 3
+ * a 0 0 1 1 1 1 4 4
+ * g 0 0 0 0 1 1 1 5
+ *
+ * dp[t.length() + 1][s.length() + 1] : dp[i][j]代表t[0-i]在s[0-j]中的出现的次数
+ * 如果某一位t[i]==s[j],则此时的次数=dp[i-1][j-1]+dp[i][j-1]
+ * 如果某一位t[i]!=s[j],则此时的次数=dp[i][j-1]
+ *
+ * 执行用时 :7 ms, 在所有 java 提交中击败了79.83%的用户
+ * 内存消耗 :35.8 MB, 在所有 java 提交中击败了85.40%的用户
+ *
+ * @param s
+ * @param t
+ * @return
+ */
+ public int numDistinct2(String s, String t) {
+ int[][] dp = new int[t.length() + 1][s.length() + 1];
+ for (int j = 0; j < s.length() + 1; j++) dp[0][j] = 1;
+ for (int i = 1; i < t.length() + 1; i++) {
+ for (int j = 1; j < s.length() + 1; j++) {
+ if (t.charAt(i - 1) == s.charAt(j - 1)) {
+ dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
+ } else {
+ dp[i][j] = dp[i][j - 1];
+ }
+ }
+ }
+ return dp[t.length()][s.length()];
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_116_connect.java b/src/pp/arithmetic/leetcode/_116_connect.java
new file mode 100644
index 0000000..27b27dd
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_116_connect.java
@@ -0,0 +1,81 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.model.Node;
+
+/**
+ * Created by wangpeng on 2019-12-14.
+ * 116. 填充每个节点的下一个右侧节点指针
+ *
+ * 给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
+ *
+ * struct Node {
+ * int val;
+ * Node *left;
+ * Node *right;
+ * Node *next;
+ * }
+ * 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
+ *
+ * 初始状态下,所有 next 指针都被设置为 NULL。
+ *
+ *
+ *
+ * 示例:
+ *
+ * https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/02/15/116_sample.png
+ *
+ *
+ * 输入:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":{"$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{"$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}
+ *
+ * 输出:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":{"$id":"4","left":null,"next":{"$id":"5","left":null,"next":{"$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{"$id":"7","left":{"$ref":"5"},"next":null,"right":{"$ref":"6"},"val":3},"right":{"$ref":"4"},"val":2},"next":null,"right":{"$ref":"7"},"val":1}
+ *
+ * 解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
+ *
+ *
+ * 提示:
+ *
+ * 你只能使用常量级额外空间。
+ * 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _116_connect {
+
+ public static void main(String[] args) {
+ _116_connect connect = new _116_connect();
+ Node node = new Node(1);
+ node.left = new Node(2);
+ node.right = new Node(3);
+ node.left.left = new Node(4);
+ node.left.right = new Node(5);
+ node.right.left = new Node(6);
+ node.right.right = new Node(7);
+ connect.connect(node);
+ System.out.println();
+ }
+
+ /**
+ * 解题思路:
+ * 总结题意:BFS遍历的时候将每一层的节点用next指针关联起来,难点是只能使用常量级空间
+ * 1、将左子树的最后侧,右子树的最左侧连接,同级向下一层层循环
+ * 2、同理作用于根节点的左右子树
+ *
+ * @param root
+ * @return
+ */
+ public Node connect(Node root) {
+ if (root == null) return null;
+ Node left = root.left;
+ Node right = root.right;
+ while (left != null) {
+ left.next = right;
+ left = left.right;
+ right = right.left;
+ }
+ connect(root.left);
+ connect(root.right);
+ return root;
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_117_connect.java b/src/pp/arithmetic/leetcode/_117_connect.java
new file mode 100644
index 0000000..8db4604
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_117_connect.java
@@ -0,0 +1,97 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.model.Node;
+
+/**
+ * Created by wangpeng on 2019-12-16.
+ * 117. 填充每个节点的下一个右侧节点指针 II
+ *
+ * 给定一个二叉树
+ *
+ * struct Node {
+ * int val;
+ * Node *left;
+ * Node *right;
+ * Node *next;
+ * }
+ * 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
+ *
+ * 初始状态下,所有 next 指针都被设置为 NULL。
+ *
+ *
+ *
+ * 进阶:
+ *
+ * 你只能使用常量级额外空间。
+ * 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
+ *
+ *
+ * 示例:
+ *
+ * https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/02/15/117_sample.png
+ *
+ * 输入:root = [1,2,3,4,5,null,7]
+ * 输出:[1,#,2,3,#,4,5,7,#]
+ * 解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
+ *
+ *
+ * 提示:
+ *
+ * 树中的节点数小于 6000
+ * -100 <= node.val <= 100
+ *
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _117_connect {
+
+ public static void main(String[] args) {
+ //[1,2,3,4,5,null,6,7,null,null,null,null,8]
+ //[1,#,2,3,#,4,5,6,#,7,#]
+ //[1,#,2,3,#,4,5,6,#,7,8,#]
+ _117_connect connect = new _117_connect();
+ Node node = new Node(1);
+ node.left = new Node(2);
+ node.right = new Node(3);
+ node.left.left = new Node(4);
+ node.left.right = new Node(5);
+ node.right.right = new Node(6);
+ node.left.left.left = new Node(7);
+ node.right.right.right = new Node(8);
+ connect.connect(node);
+ System.out.println();
+ }
+
+ /**
+ * 解题思路:题目和{@link _116_connect}类似,唯一区别是此题不是完美二叉树,可能存在子树为空,所以不能使用116的解法,
+ * 得求解每一层需要连接的左右子树
+ *
+ * @param root
+ * @return
+ */
+ public Node connect(Node root) {
+ Node cur = root;
+ while (cur != null) {
+ Node dummy = new Node();
+ Node tail = dummy;
+ //遍历 cur 的当前层
+ while (cur != null) {
+ if (cur.left != null) {
+ tail.next = cur.left;
+ tail = tail.next;
+ }
+ if (cur.right != null) {
+ tail.next = cur.right;
+ tail = tail.next;
+ }
+ cur = cur.next;
+ }
+ //更新 cur 到下一层
+ cur = dummy.next;
+ }
+ return root;
+ }
+
+}
diff --git a/src/pp/arithmetic/leetcode/_118_generate.java b/src/pp/arithmetic/leetcode/_118_generate.java
new file mode 100644
index 0000000..02952cb
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_118_generate.java
@@ -0,0 +1,74 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.Util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by wangpeng on 2019-12-18.
+ * 118. 杨辉三角
+ *
+ *
+ * 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
+ *
+ * https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif
+ *
+ * 在杨辉三角中,每个数是它左上方和右上方的数的和。
+ *
+ * 示例:
+ *
+ * 输入: 5
+ * 输出:
+ * [
+ * [1],
+ * [1,1],
+ * [1,2,1],
+ * [1,3,3,1],
+ * [1,4,6,4,1]
+ * ]
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/pascals-triangle
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _118_generate {
+
+
+ public static void main(String[] args) {
+ _118_generate generate = new _118_generate();
+ List
+ * 编写一个可以从 1 到 n 输出代表这个数字的字符串的程序,但是:
+ *
+ * 如果这个数字可以被 3 整除,输出 "fizz"。
+ * 如果这个数字可以被 5 整除,输出 "buzz"。
+ * 如果这个数字可以同时被 3 和 5 整除,输出 "fizzbuzz"。
+ * 例如,当 n = 15,输出: 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz。
+ *
+ * 假设有这么一个类:
+ *
+ * class FizzBuzz {
+ * public FizzBuzz(int n) { ... } // constructor
+ * public void fizz(printFizz) { ... } // only output "fizz"
+ * public void buzz(printBuzz) { ... } // only output "buzz"
+ * public void fizzbuzz(printFizzBuzz) { ... } // only output "fizzbuzz"
+ * public void number(printNumber) { ... } // only output the numbers
+ * }
+ * 请你实现一个有四个线程的多线程版 FizzBuzz, 同一个 FizzBuzz 实例会被如下四个线程使用:
+ *
+ * 线程A将调用 fizz() 来判断是否能被 3 整除,如果可以,则输出 fizz。
+ * 线程B将调用 buzz() 来判断是否能被 5 整除,如果可以,则输出 buzz。
+ * 线程C将调用 fizzbuzz() 来判断是否同时能被 3 和 5 整除,如果可以,则输出 fizzbuzz。
+ * 线程D将调用 number() 来实现输出既不能被 3 整除也不能被 5 整除的数字。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/fizz-buzz-multithreaded
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _1195_FizzBuzz {
+
+ public static void main(String[] args) {
+ FizzBuzz fizzBuzz = new FizzBuzz(16);
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ try {
+ fizzBuzz.fizz(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("fizz");
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ try {
+ fizzBuzz.buzz(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("buzz");
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ try {
+ fizzBuzz.fizzbuzz(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("fizzbuzz");
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ try {
+ fizzBuzz.number(new IntConsumer() {
+ @Override
+ public void accept(int value) {
+ System.out.println(value);
+ }
+ });
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
+
+ /**
+ * 解题思路:对于多线程的问题,无非是加锁、等待、解锁、通知,
+ */
+ static class FizzBuzz {
+ private int n;
+ private int pn = 1;
+ private Semaphore fs = new Semaphore(0);
+ private Semaphore bs = new Semaphore(0);
+ private Semaphore fbs = new Semaphore(0);
+ private Semaphore ns = new Semaphore(1);
+
+ public FizzBuzz(int n) {
+ this.n = n;
+ }
+
+ // printFizz.run() outputs "fizz".
+ public void fizz(Runnable printFizz) throws InterruptedException {
+ while (pn <= n) {
+ fs.acquire();
+ if (pn > n) break;
+ printFizz.run();
+ pn++;
+ notifyPrint();
+ }
+ }
+
+ // printBuzz.run() outputs "buzz".
+ public void buzz(Runnable printBuzz) throws InterruptedException {
+ while (pn <= n) {
+ bs.acquire();
+ if (pn > n) break;
+ printBuzz.run();
+ pn++;
+ notifyPrint();
+ }
+ }
+
+ // printFizzBuzz.run() outputs "fizzbuzz".
+ public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
+ while (pn <= n) {
+ fbs.acquire();
+ if (pn > n) break;
+ printFizzBuzz.run();
+ pn++;
+ notifyPrint();
+ }
+ }
+
+ // printNumber.accept(x) outputs "x", where x is an integer.
+ public void number(IntConsumer printNumber) throws InterruptedException {
+ while (pn <= n) {
+ ns.acquire();
+ if (pn > n) break;
+ printNumber.accept(pn);
+ pn++;
+ notifyPrint();
+ }
+ }
+
+ private void notifyPrint() {
+ if (pn > n) {
+ fs.release();
+ bs.release();
+ fbs.release();
+ ns.release();
+ return;
+ }
+ boolean m3 = pn % 3 == 0;
+ boolean m5 = pn % 5 == 0;
+ if (m3 && m5) {
+ fbs.release();
+ } else if (m3) {
+ fs.release();
+ } else if (m5) {
+ bs.release();
+ } else {
+ ns.release();
+ }
+ }
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_119_getRow.java b/src/pp/arithmetic/leetcode/_119_getRow.java
new file mode 100644
index 0000000..4ab63d3
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_119_getRow.java
@@ -0,0 +1,61 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.Util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by wangpeng on 2019-12-18.
+ * 119. 杨辉三角 II
+ *
+ * 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。
+ *
+ * https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif
+ *
+ * 在杨辉三角中,每个数是它左上方和右上方的数的和。
+ *
+ * 示例:
+ *
+ * 输入: 3
+ * 输出: [1,3,3,1]
+ * 进阶:
+ *
+ * 你可以优化你的算法到 O(k) 空间复杂度吗?
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/pascals-triangle-ii
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _119_getRow {
+
+ public static void main(String[] args) {
+ _119_getRow getRow = new _119_getRow();
+ Util.printList(getRow.getRow(6));
+ }
+
+ /**
+ * 解题思路:
+ * 最简单的就是像 {@link _118_generate} 中解题方式,求出第row行的结果,可是期望 O(k) 空间复杂度,这是难点
+ * 考虑能不能通过规律找出直接计算第row行的结果?
+ * 通过杨辉三角规律可知,第i行第j个得数字结果是(i,j)的组合数
+ *
+ * 执行用时 :1 ms, 在所有 java 提交中击败了93.68%的用户
+ * 内存消耗 :33.6 MB, 在所有 java 提交中击败了23.63%的用户
+ *
+ * @param rowIndex
+ * @return
+ */
+ public List
+ * 给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
+ *
+ * 图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
+ *
+ * class Node {
+ * public int val;
+ * public List
+ * 测试用例格式:
+ *
+ * 简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1,第二个节点值为 2,以此类推。该图在测试用例中使用邻接列表表示。
+ *
+ * 邻接列表是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
+ *
+ * 给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。
+ *
+ *
+ *
+ * 示例 1:
+ *
+ *
+ *
+ * 输入:adjList = [[2,4],[1,3],[2,4],[1,3]]
+ * 输出:[[2,4],[1,3],[2,4],[1,3]]
+ * 解释:
+ * 图中有 4 个节点。
+ * 节点 1 的值是 1,它有两个邻居:节点 2 和 4 。
+ * 节点 2 的值是 2,它有两个邻居:节点 1 和 3 。
+ * 节点 3 的值是 3,它有两个邻居:节点 2 和 4 。
+ * 节点 4 的值是 4,它有两个邻居:节点 1 和 3 。
+ * 示例 2:
+ *
+ *
+ *
+ * 输入:adjList = [[]]
+ * 输出:[[]]
+ * 解释:输入包含一个空列表。该图仅仅只有一个值为 1 的节点,它没有任何邻居。
+ * 示例 3:
+ *
+ * 输入:adjList = []
+ * 输出:[]
+ * 解释:这个图是空的,它不含任何节点。
+ * 示例 4:
+ *
+ *
+ *
+ * 输入:adjList = [[2],[1]]
+ * 输出:[[2],[1]]
+ *
+ *
+ * 提示:
+ *
+ * 节点数介于 1 到 100 之间。
+ * 每个节点值都是唯一的。
+ * 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
+ * 由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
+ * 图是连通图,你可以从给定节点访问到所有节点。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/clone-graph
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _133_cloneGraph {
+
+ public static void main(String[] args) {
+ _133_cloneGraph cloneGraph = new _133_cloneGraph();
+ Node node1 = new Node();
+ node1.val = 1;
+ Node node2 = new Node();
+ node2.val = 2;
+ Node node3 = new Node();
+ node3.val = 3;
+ Node node4 = new Node();
+ node4.val = 4;
+ //[[2,4],[1,3],[2,4],[1,3]]
+ node1.neighbors = new ArrayList<>();
+ node1.neighbors.add(node2);
+ node1.neighbors.add(node4);
+ node2.neighbors = new ArrayList<>();
+ node2.neighbors.add(node1);
+ node2.neighbors.add(node3);
+ node3.neighbors = new ArrayList<>();
+ node3.neighbors.add(node2);
+ node3.neighbors.add(node4);
+ node4.neighbors = new ArrayList<>();
+ node4.neighbors.add(node1);
+ node4.neighbors.add(node3);
+ Node clone = cloneGraph.cloneGraph(node1);
+ System.out.println();
+ }
+
+ /**
+ * 解题思路:
+ * 先花了很大的力气读题目,最后发现就是图的深度遍历,由于每个节点值都是唯一的,用一个HashMap保存遍历过的节点,防止无限循环
+ * @param node
+ * @return
+ */
+ public Node cloneGraph(Node node) {
+ if (node == null){
+ return null;
+ }
+ HashMap
+ * 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。
+ *
+ * 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列。格雷编码序列必须以 0 开头。
+ *
+ * 示例 1:
+ *
+ * 输入: 2
+ * 输出: [0,1,3,2]
+ * 解释:
+ * 00 - 0
+ * 01 - 1
+ * 11 - 3
+ * 10 - 2
+ *
+ * 对于给定的 n,其格雷编码序列并不唯一。
+ * 例如,[0,2,3,1] 也是一个有效的格雷编码序列。
+ *
+ * 00 - 0
+ * 10 - 2
+ * 11 - 3
+ * 01 - 1
+ * 示例 2:
+ *
+ * 输入: 0
+ * 输出: [0]
+ * 解释: 我们定义格雷编码序列必须以 0 开头。
+ * 给定编码总位数为 n 的格雷编码序列,其长度为 2^n。当 n = 0 时,长度为 2^0 = 1。
+ * 因此,当 n = 0 时,其格雷编码序列为 [0]。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/gray-code
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _89_grayCode {
+
+ public static void main(String[] args) {
+ _89_grayCode grayCode = new _89_grayCode();
+ Util.printList(grayCode.grayCode(2));
+ }
+
+ /**
+ * 解题思路:
+ *
+ * @param n
+ * @return
+ */
+ public List
+ * 给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
+ *
+ * 示例 1:
+ *
+ * 输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
+ * 输出: true
+ * 示例 2:
+ *
+ * 输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
+ * 输出: false
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/interleaving-string
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _97_isInterleave {
+
+ public static void main(String[] args) {
+ _97_isInterleave isInterleave = new _97_isInterleave();
+ System.out.println(isInterleave.isInterleave("a", "bbbbbbb", "abbbbbba"));
+ System.out.println(isInterleave.isInterleave("aabcc", "dbbca", "aadbbcbcac"));
+ System.out.println(isInterleave.isInterleave("aabcc", "dbbca", "aadbbbaccc"));
+ System.out.println(isInterleave.isInterleave("a", "", "c"));
+ System.out.println(isInterleave.isInterleave("ab", "bc", "bbac"));
+ }
+
+ /**
+ * 解题思路:循环比较,回溯算法
+ * 先比较第i位+比较后面的位,如果第i位后面的都能匹配上,加上第i位也能匹配上,那么就能完全匹配。i从0开始
+ *
+ * 执行用时 :1362 ms, 在所有 java 提交中击败了5.10%的用户
+ * 内存消耗 :34.7 MB, 在所有 java 提交中击败了42.29%的用户
+ *
+ * @param s1、
+ * @param s2
+ * @param s3
+ * @return
+ */
+ public boolean isInterleave(String s1, String s2, String s3) {
+ if (s3.length() != s1.length() + s2.length()) return false;
+ return isInterleave(s1, s2, s3, 0, 0, 0);
+ }
+
+ private boolean isInterleave(String s1, String s2, String s3, int i1, int i2, int i3) {
+ if (i3 == s3.length()) return true;
+ char c3 = s3.charAt(i3);
+ if (((i1 < s1.length() && s1.charAt(i1) != c3) || "".equals(s1)) &&
+ ((i2 < s2.length() && s2.charAt(i2) != c3) || "".equals(s2))) {
+ return false;
+ }
+ if (i1 < s1.length() && s1.charAt(i1) == c3 && isInterleave(s1, s2, s3, i1 + 1, i2, i3 + 1)) {
+ return true;
+ }
+ if (i2 < s2.length() && s2.charAt(i2) == c3 && isInterleave(s1, s2, s3, i1, i2 + 1, i3 + 1)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/pp/arithmetic/leetcode/_99_recoverTree.java b/src/pp/arithmetic/leetcode/_99_recoverTree.java
new file mode 100644
index 0000000..50d5d6e
--- /dev/null
+++ b/src/pp/arithmetic/leetcode/_99_recoverTree.java
@@ -0,0 +1,153 @@
+package pp.arithmetic.leetcode;
+
+import pp.arithmetic.Util;
+import pp.arithmetic.model.TreeNode;
+
+/**
+ * Created by wangpeng on 2019-12-01.
+ * 99. 恢复二叉搜索树
+ *
+ * 二叉搜索树中的两个节点被错误地交换。
+ *
+ * 请在不改变其结构的情况下,恢复这棵树。
+ *
+ * 示例 1:
+ *
+ * 输入: [1,3,null,null,2]
+ *
+ * 1
+ * /
+ * 3
+ * \
+ * 2
+ *
+ * 输出: [3,1,null,null,2]
+ *
+ * 3
+ * /
+ * 1
+ * \
+ * 2
+ * 示例 2:
+ *
+ * 输入: [3,1,4,null,null,2]
+ *
+ * 3
+ * / \
+ * 1 4
+ * /
+ * 2
+ *
+ * 输出: [2,1,4,null,null,3]
+ *
+ * 2
+ * / \
+ * 1 4
+ * /
+ * 3
+ * 进阶:
+ *
+ * 使用 O(n) 空间复杂度的解法很容易实现。
+ * 你能想出一个只使用常数空间的解决方案吗?
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/recover-binary-search-tree
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _99_recoverTree {
+
+ public static void main(String[] args) {
+ TreeNode treeNode = new TreeNode(1);
+ treeNode.left = new TreeNode(3);
+ treeNode.left.right = new TreeNode(2);
+ _99_recoverTree recoverTree = new _99_recoverTree();
+ recoverTree.recoverTree(treeNode);
+ Util.printTree(treeNode);
+ }
+
+ /**
+ * 解题思路:
+ * 分:几种情况
+ * 1、根节点和左子树的某个数字交换 -> 由于根节点大于左子树中的所有数,所以交换后我们只要找左子树中最大的那个数,就是所交换的那个数
+ * 2、根节点和右子树的某个数字交换 -> 由于根节点小于右子树中的所有数,所以交换后我们只要在右子树中最小的那个数,就是所交换的那个数
+ * 3、左子树和右子树的两个数字交换 -> 找左子树中最大的数,右子树中最小的数,即对应两个交换的数
+ * 4、左子树中的两个数字交换
+ * 5、右子树中的两个数字交换
+ * @param root
+ */
+ public void recoverTree(TreeNode root) {
+ if (root == null) {
+ return;
+ }
+ //寻找左子树中最大的节点
+ TreeNode maxLeft = getMaxOfBST(root.left);
+ //寻找右子树中最小的节点
+ TreeNode minRight = getMinOfBST(root.right);
+
+ if (minRight != null && maxLeft != null) {
+ //左边的大于根节点,右边的小于根节点,对应情况 3,左右子树中的两个数字交换
+ if ( maxLeft.val > root.val && minRight.val < root.val) {
+ int temp = minRight.val;
+ minRight.val = maxLeft.val;
+ maxLeft.val = temp;
+ }
+ }
+
+ if (maxLeft != null) {
+ //左边最大的大于根节点,对应情况 1,根节点和左子树的某个数做了交换
+ if (maxLeft.val > root.val) {
+ int temp = maxLeft.val;
+ maxLeft.val = root.val;
+ root.val = temp;
+ }
+ }
+
+ if (minRight != null) {
+ //右边最小的小于根节点,对应情况 2,根节点和右子树的某个数做了交换
+ if (minRight.val < root.val) {
+ int temp = minRight.val;
+ minRight.val = root.val;
+ root.val = temp;
+ }
+ }
+ //对应情况 4,左子树中的两个数进行了交换
+ recoverTree(root.left);
+ //对应情况 5,右子树中的两个数进行了交换
+ recoverTree(root.right);
+
+ }
+ //寻找树中最小的节点
+ private TreeNode getMinOfBST(TreeNode root) {
+ if (root == null) {
+ return null;
+ }
+ TreeNode minLeft = getMinOfBST(root.left);
+ TreeNode minRight = getMinOfBST(root.right);
+ TreeNode min = root;
+ if (minLeft != null && min.val > minLeft.val) {
+ min = minLeft;
+ }
+ if (minRight != null && min.val > minRight.val) {
+ min = minRight;
+ }
+ return min;
+ }
+
+ //寻找树中最大的节点
+ private TreeNode getMaxOfBST(TreeNode root) {
+ if (root == null) {
+ return null;
+ }
+ TreeNode maxLeft = getMaxOfBST(root.left);
+ TreeNode maxRight = getMaxOfBST(root.right);
+ TreeNode max = root;
+ if (maxLeft != null && max.val < maxLeft.val) {
+ max = maxLeft;
+ }
+ if (maxRight != null && max.val < maxRight.val) {
+ max = maxRight;
+ }
+ return max;
+ }
+
+}
diff --git a/src/pp/arithmetic/model/Node.java b/src/pp/arithmetic/model/Node.java
new file mode 100644
index 0000000..15ac2de
--- /dev/null
+++ b/src/pp/arithmetic/model/Node.java
@@ -0,0 +1,24 @@
+package pp.arithmetic.model;
+
+/**
+ * Created by wangpeng on 2019-12-14.
+ */
+public class Node {
+ public int val;
+ public Node left;
+ public Node right;
+ public Node next;
+
+ public Node() {}
+
+ public Node(int _val) {
+ val = _val;
+ }
+
+ public Node(int _val, Node _left, Node _right, Node _next) {
+ val = _val;
+ left = _left;
+ right = _right;
+ next = _next;
+ }
+}
diff --git a/src/pp/arithmetic/offer/_03_findRepeatNumber.java b/src/pp/arithmetic/offer/_03_findRepeatNumber.java
new file mode 100644
index 0000000..8fbedfa
--- /dev/null
+++ b/src/pp/arithmetic/offer/_03_findRepeatNumber.java
@@ -0,0 +1,124 @@
+package pp.arithmetic.offer;
+
+import java.util.HashMap;
+
+/**
+ * Created by wangpeng on 2020-07-28.
+ * 剑指 Offer 03. 数组中重复的数字
+ *
+ * 找出数组中重复的数字。
+ *
+ *
+ * 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
+ *
+ * 示例 1:
+ *
+ * 输入:
+ * [2, 3, 1, 0, 2, 5, 3]
+ * 输出:2 或 3
+ *
+ *
+ * 限制:
+ *
+ * 2 <= n <= 100000
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _03_findRepeatNumber {
+
+ public static void main(String[] args) {
+ _03_findRepeatNumber findRepeatNumber = new _03_findRepeatNumber();
+ int repeatNumber = findRepeatNumber.findRepeatNumber(new int[]{2, 3, 0, 1, 2, 3, 4, 5, 3});
+ System.out.println(repeatNumber);
+ int repeatNumber2 = findRepeatNumber.findRepeatNumber2(new int[]{2, 3, 0, 1, 2, 3, 4, 5, 3});
+ System.out.println(repeatNumber2);
+ int repeatNumber3 = findRepeatNumber.findRepeatNumber3(new int[]{2, 3, 0, 1, 2, 3, 4, 5, 3});
+ System.out.println(repeatNumber3);
+ }
+
+ /**
+ * 解题思路:
+ * 方案一:最直接的方式,使用一个HashMap进行存储遍历过的数字,性能肯定不会差,内存占用会高
+ *
+ * 执行用时:13 ms, 在所有 Java 提交中击败了8.98%的用户
+ * 内存消耗:48.7 MB, 在所有 Java 提交中击败了100.00%的用户
+ *
+ * 执行结果有点出人意料,用时偏高
+ *
+ * 优化方案二:{@link _03_findRepeatNumber#findRepeatNumber2(int[])}
+ *
+ * @param nums
+ * @return
+ */
+ public int findRepeatNumber(int[] nums) {
+ HashMap
+ * 剑指 Offer 12. 矩阵中的路径
+ *
+ * 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。
+ * 如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
+ *
+ * [["a","b","c","e"],
+ * ["s","f","c","s"],
+ * ["a","d","e","e"]]
+ *
+ * 但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
+ *
+ *
+ *
+ * 示例 1:
+ *
+ * 输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
+ * 输出:true
+ * 示例 2:
+ *
+ * 输入:board = [["a","b"],["c","d"]], word = "abcd"
+ * 输出:false
+ * 提示:
+ *
+ * 1 <= board.length <= 200
+ * 1 <= board[i].length <= 200
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _12_exist {
+
+ public static void main(String[] args) {
+ _12_exist exist = new _12_exist();
+// char[][] board = new char[][]{
+// {'A', 'B', 'C', 'E'},
+// {'S', 'F', 'C', 'S'},
+// {'A', 'D', 'E', 'E'}
+// };
+// System.out.println(exist.exist(board,"ABFACED"));
+// System.out.println(exist.exist(new char[][]{
+// {'a','b'},
+// {'c','d'}
+// },"abcd"));
+ System.out.println(exist.exist(new char[][]{
+ {'C','A','A'},
+ {'A','A','A'},
+ {'B','C','D'}
+ },"AAB"));
+ }
+
+ /**
+ * 解题思路:
+ * 从board的[0,0]开始向上、左、下、右进行深度遍历,逐步去匹配word中的字符,新建个history保存遍历路径,防止死循环
+ *
+ * @param board
+ * @param word
+ * @return
+ */
+ public boolean exist(char[][] board, String word) {
+ if (board == null || board.length == 0) return false;
+ int[][] history = new int[board.length][board[0].length];
+ return dfs(board, word, history, 0, 0, 0);
+ }
+
+ private boolean dfs(char[][] board, String word, int[][] history, int wi, int nx, int ny) {
+ if (wi >= word.length()) {
+ //word遍历结束才返回true
+ return true;
+ }
+ //遍历越界
+ if (nx < 0 || nx >= board.length || ny < 0 || ny >= board[nx].length) return false;
+ //之前走过这个位置
+ if (history[nx][ny] == 1) return false;
+ if (board[nx][ny] == word.charAt(wi)) {
+ history[nx][ny] = 1;
+ if (dfs(board, word, history, wi + 1, nx, ny + 1)
+ || dfs(board, word, history, wi + 1, nx + 1, ny)
+ || dfs(board, word, history, wi + 1, nx, ny - 1)
+ || dfs(board, word, history, wi + 1, nx - 1, ny)) {
+ return true;
+ }
+ history[nx][ny] = 0;
+ }
+ if (wi == 0) {
+ //定位首个字符的标识位
+ if (nx < board.length - 1) {
+ if (dfs(board, word, history, wi, nx + 1, ny)) {
+ return true;
+ }
+ } else if (ny < board[0].length - 1) {
+ if (dfs(board, word, history, wi, 0, ny + 1)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/src/pp/arithmetic/offer/_13_movingCount.java b/src/pp/arithmetic/offer/_13_movingCount.java
new file mode 100644
index 0000000..e89db86
--- /dev/null
+++ b/src/pp/arithmetic/offer/_13_movingCount.java
@@ -0,0 +1,83 @@
+package pp.arithmetic.offer;
+
+/**
+ * Created by wangpeng on 2020-08-06.
+ *
+ * 剑指 Offer 13. 机器人的运动范围
+ *
+ * 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),
+ * 也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
+ *
+ *
+ *
+ * 示例 1:
+ *
+ * 输入:m = 2, n = 3, k = 1
+ * 输出:3
+ * 示例 2:
+ *
+ * 输入:m = 3, n = 1, k = 0
+ * 输出:1
+ * 提示:
+ *
+ * 1 <= n,m <= 100
+ * 0 <= k <= 20
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _13_movingCount {
+
+ public static void main(String[] args) {
+ _13_movingCount movingCount = new _13_movingCount();
+ System.out.println(movingCount.movingCount(2,3,1));
+ System.out.println(movingCount.movingCount(3,1,0));
+ System.out.println(movingCount.movingCount(1,2,1));
+ System.out.println(movingCount.movingCount(10,10,2));
+ System.out.println(movingCount.movingCount(16,8,4));
+ }
+
+ private int retVal = 0;
+
+ /**
+ * 解题思路:
+ * 使用int[m][n]大小的数组保存行进记录,上下左右进行DFS,不满足条件的跳过
+ * 需要注意的可能中间某些行和列相加也满足条件,所以需要整个行和列都需要遍历完(不需要考虑,题中是从0,0开始的)
+ *
+ * @param m
+ * @param n
+ * @param k
+ * @return
+ */
+ public int movingCount(int m, int n, int k) {
+ if (k < 0 || m <=0 || n<=0) return 0;
+ retVal = 0;
+ int[][] history = new int[m][n];
+ dfs(0,0,m,n,k,history);
+ return retVal;
+ }
+
+ private void dfs(int cx, int cy, int m, int n, int k, int[][] history) {
+ if (cx < 0 || cx >= m || cy < 0 || cy >= n) return;
+ if (add(cx, cy) > k) return;
+ if (history[cx][cy] == 1) return;
+ history[cx][cy] = 1;
+ retVal++;
+ dfs(cx, cy + 1, m, n, k, history);
+ dfs(cx + 1, cy, m, n, k, history);
+ dfs(cx, cy - 1, m, n, k, history);
+ dfs(cx - 1, cy, m, n, k, history);
+ }
+
+ private int add(int x, int y) {
+ int retVal = 0;
+ retVal += x / 100;
+ retVal += (x - x / 100 * 100) / 10;
+ retVal += x - x / 100 * 100 - (x - x / 100 * 100) / 10 * 10;
+ retVal += y / 100;
+ retVal += (y - y / 100 * 100) / 10;
+ retVal += y - y / 100 * 100 - (y - y / 100 * 100) / 10 * 10;
+ return retVal;
+ }
+}
diff --git a/src/pp/arithmetic/offer/_14_1_cuttingRope.java b/src/pp/arithmetic/offer/_14_1_cuttingRope.java
new file mode 100644
index 0000000..939abcc
--- /dev/null
+++ b/src/pp/arithmetic/offer/_14_1_cuttingRope.java
@@ -0,0 +1,68 @@
+package pp.arithmetic.offer;
+
+/**
+ * Created by wangpeng on 2020-08-07.
+ *
+ * 剑指 Offer 14- I. 剪绳子
+ *
+ * 给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
+ *
+ * 示例 1:
+ *
+ * 输入: 2
+ * 输出: 1
+ * 解释: 2 = 1 + 1, 1 × 1 = 1
+ * 示例 2:
+ *
+ * 输入: 10
+ * 输出: 36
+ * 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
+ * 提示:
+ *
+ * 2 <= n <= 58
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _14_1_cuttingRope {
+
+ public static void main(String[] args) {
+ _14_1_cuttingRope cuttingRope = new _14_1_cuttingRope();
+ System.out.println(cuttingRope.cuttingRope(8));
+ System.out.println(cuttingRope.cuttingRope(10));
+ System.out.println(cuttingRope.cuttingRope(14));
+ System.out.println(cuttingRope.cuttingRope(58));
+ }
+
+ /**
+ * 解题思路:
+ * 手动模拟了从2-10的最大乘积数字拆解,发现了一个现象:
+ * 对于数字n,n一直除以2到1为止,得到的数字就是最大的乘积,举例如下:
+ * 数字n 2 3 4 5 6 7 8 9 10
+ * 乘积 1,1 1,2 2,2 2,3 3,3 3,4(2,2) 4(2,2),4(2,2) 4,5(2,3) 5(2,3),5(2,3)
+ * 发现到了后面的最大乘积可以利用之前的计算好的结果,从而得出动态规划转移方程
+ * dp[i]=dp[i/2]*dp[i-i/2](i>3)
+ * 上面有问题,例如8的最大值不是除以2得到4*4=16,而是3*2*3=18,所以得双重循环取所有情况的最大值
+ * for (int j = 1; j <= i / 2; j++) {
+ * dp[i] = Math.max(dp[i], dp[j] * dp[i - j]);
+ * }
+ *
+ * @param n
+ * @return
+ */
+ public int cuttingRope(int n) {
+ if (n <= 3) return n - 1;
+ int[] dp = new int[n + 1];
+ //初始化,1,2,3特殊处理
+ dp[1] = 1;
+ dp[2] = 2;
+ dp[3] = 3;
+ for (int i = 4; i <= n; i++) {
+ for (int j = 1; j <= i / 2; j++) {
+ dp[i] = Math.max(dp[i], dp[j] * dp[i - j]);
+ }
+ }
+ return dp[n];
+ }
+}
diff --git a/src/pp/arithmetic/offer/_15_hammingWeight.java b/src/pp/arithmetic/offer/_15_hammingWeight.java
new file mode 100644
index 0000000..bfae0b4
--- /dev/null
+++ b/src/pp/arithmetic/offer/_15_hammingWeight.java
@@ -0,0 +1,57 @@
+package pp.arithmetic.offer;
+
+/**
+ * Created by wangpeng on 2020-08-10.
+ * 剑指 Offer 15. 二进制中1的个数
+ *
+ * 请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
+ *
+ * 示例 1:
+ *
+ * 输入:00000000000000000000000000001011
+ * 输出:3
+ * 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
+ * 示例 2:
+ *
+ * 输入:00000000000000000000000010000000
+ * 输出:1
+ * 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
+ * 示例 3:
+ *
+ * 输入:11111111111111111111111111111101
+ * 输出:31
+ * 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _15_hammingWeight {
+
+ public static void main(String[] args) {
+ _15_hammingWeight hammingWeight = new _15_hammingWeight();
+ System.out.println(hammingWeight.hammingWeight(11));
+ System.out.println(hammingWeight.hammingWeight(128));
+// System.out.println(hammingWeight.hammingWeight(4294967293));
+ }
+
+
+ /**
+ * 解题思路:
+ * 如果n%2!=0,则1的个数+1,直到n=1
+ *
+ * 注意无符号的,对应int会超 右移动使用>>>(无符号右移)
+ * @param n
+ * @return
+ */
+ // you need to treat n as an unsigned value
+ public int hammingWeight(int n) {
+ int retVal = 0;
+ while (n != 0) {
+ retVal += n & 1;
+ n = n >>> 1;
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/pp/arithmetic/offer/_16_myPow.java b/src/pp/arithmetic/offer/_16_myPow.java
new file mode 100644
index 0000000..0a49745
--- /dev/null
+++ b/src/pp/arithmetic/offer/_16_myPow.java
@@ -0,0 +1,71 @@
+package pp.arithmetic.offer;
+
+/**
+ * Created by wangpeng on 2020-08-11.
+ *
+ * 剑指 Offer 16. 数值的整数次方
+ *
+ * 实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
+ *
+ *
+ *
+ * 示例 1:
+ *
+ * 输入: 2.00000, 10
+ * 输出: 1024.00000
+ * 示例 2:
+ *
+ * 输入: 2.10000, 3
+ * 输出: 9.26100
+ * 示例 3:
+ *
+ * 输入: 2.00000, -2
+ * 输出: 0.25000
+ * 解释: 2-2 = 1/22 = 1/4 = 0.25
+ *
+ *
+ * 说明:
+ *
+ * -100.0 < x < 100.0
+ * n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1] 。
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _16_myPow {
+
+ public static void main(String[] args) {
+ _16_myPow myPow = new _16_myPow();
+ System.out.println(myPow.myPow(2.0,10));
+ System.out.println(myPow.myPow(2.1,3));
+ System.out.println(myPow.myPow(2.0,-2));
+ System.out.println(myPow.myPow(0.00001, 2147483647));
+ System.out.println(myPow.myPow(2, -2147483648));
+ }
+
+ /**
+ * 解题思路:
+ * 最简单的方式就是直接循环0-n,将x相乘得出结果,题目中的n范围比较大,这样子效率太低
+ * 优化:类似2分拆分,一半一半的计算结果,最终相乘
+ * @param x
+ * @param n
+ * @return
+ */
+ public double myPow(double x, int n) {
+ if (n == 0) return 1;
+ if (n<0){
+ //指数是否负数,负数需要取倒数
+ x = 1/x;
+ }
+ //是否取一半还有剩余一个
+ boolean isOdd = n % 2 != 0;
+ double v = myPow(x, Math.abs(n / 2));
+ if (isOdd) {
+ return v * v * x;
+ } else {
+ return v * v;
+ }
+ }
+
+}
diff --git a/src/pp/arithmetic/offer/_17_printNumbers.java b/src/pp/arithmetic/offer/_17_printNumbers.java
new file mode 100644
index 0000000..6eb52a1
--- /dev/null
+++ b/src/pp/arithmetic/offer/_17_printNumbers.java
@@ -0,0 +1,56 @@
+package pp.arithmetic.offer;
+
+import pp.arithmetic.Util;
+
+/**
+ * Created by wangpeng on 2020-08-11.
+ *
+ * 剑指 Offer 17. 打印从1到最大的n位数
+ *
+ * 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
+ *
+ * 示例 1:
+ *
+ * 输入: n = 1
+ * 输出: [1,2,3,4,5,6,7,8,9]
+ *
+ *
+ * 说明:
+ *
+ * 用返回一个整数列表来代替打印
+ * n 为正整数
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _17_printNumbers {
+
+ public static void main(String[] args) {
+ _17_printNumbers printNumbers = new _17_printNumbers();
+ Util.printArray(printNumbers.printNumbers(1));
+ Util.printArray(printNumbers.printNumbers(2));
+ Util.printArray(printNumbers.printNumbers(3));
+ }
+
+ /**
+ * 解题思路:
+ * 本题没有什么难度,唯一难的就是咋根据n构建出相应size的数组
+ *
+ * @param n
+ * @return
+ */
+ public int[] printNumbers(int n) {
+ char[] len = new char[n];
+ for (int i = 0; i < n; i++) {
+ len[i] = '9';
+ }
+ int size = Integer.parseInt(new String(len));
+ int[] retVal = new int[size];
+ for (int i = 0; i < size; i++) {
+ retVal[i] = i+1;
+ }
+
+ return retVal;
+ }
+}
diff --git a/src/pp/arithmetic/offer/_18_deleteNode.java b/src/pp/arithmetic/offer/_18_deleteNode.java
new file mode 100644
index 0000000..0f4dd2e
--- /dev/null
+++ b/src/pp/arithmetic/offer/_18_deleteNode.java
@@ -0,0 +1,74 @@
+package pp.arithmetic.offer;
+
+import pp.arithmetic.Util;
+import pp.arithmetic.model.ListNode;
+
+/**
+ * Created by wangpeng on 2020-09-09.
+ * 剑指 Offer 18. 删除链表的节点
+ *
+ * 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
+ *
+ * 返回删除后的链表的头节点。
+ *
+ * 注意:此题对比原题有改动
+ *
+ * 示例 1:
+ *
+ * 输入: head = [4,5,1,9], val = 5
+ * 输出: [4,1,9]
+ * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
+ * 示例 2:
+ *
+ * 输入: head = [4,5,1,9], val = 1
+ * 输出: [4,5,9]
+ * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
+ *
+ *
+ * 说明:
+ *
+ * 题目保证链表中节点的值互不相同
+ * 若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
+ *
+ * 来源:力扣(LeetCode)
+ * 链接:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof
+ * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
+ */
+public class _18_deleteNode {
+
+ public static void main(String[] args) {
+ _18_deleteNode deleteNode = new _18_deleteNode();
+ ListNode head = new ListNode(4);
+ head.next = new ListNode(5);
+ head.next.next = new ListNode(1);
+ head.next.next.next = new ListNode(9);
+ ListNode listNode = deleteNode.deleteNode(head, 4);
+ Util.printListNode(listNode);
+ }
+
+ /**
+ * 解题思路:
+ * 对于链表的问题,最核心的思想就是遍历,使用一个虚拟节点指向头结点,用来缓存返回结果
+ *
+ * @param head
+ * @param val
+ * @return
+ */
+ public ListNode deleteNode(ListNode head, int val) {
+ ListNode dummp = new ListNode(0);
+ dummp.next = head;
+ ListNode pre = dummp;
+ ListNode next = head;
+ while (next != null) {
+ if (next.val == val) {
+ pre.next = next.next;
+ next.next = null;
+ return dummp.next;
+ }
+ pre = next;
+ next = next.next;
+ }
+
+ return null;
+ }
+}
> lists) {
+ for (int i = 0; i < lists.size(); i++) {
+ System.out.print("[ ");
+ for (int j = 0; j < lists.get(i).size(); j++) {
+ System.out.print(lists.get(i).get(j) + " ");
+ }
+ System.out.print("]");
+ System.out.println();
+ }
+ }
+
public static void printStringList(List
> lists = levelOrderBottom.levelOrderBottom(node);
+ for (int i = 0; i < lists.size(); i++) {
+ Util.printList(lists.get(i));
+ }
+ }
+
+ /**
+ * 解题思路:
+ * 树的问题就是遍历,本题用树的广度遍历(BFS)
+ * BFS遍历依赖队列保存一层的节点
+ *
+ * @param root
+ * @return
+ */
+ public List
> levelOrderBottom(TreeNode root) {
+ List
> retList = new ArrayList<>();
+ if (root == null) return retList;
+ Queue
> list = generate.generate(5);
+ for (int i = 0; i < list.size(); i++) {
+ Util.printList(list.get(i));
+ }
+ }
+
+ /**
+ * 解题思路:
+ * 0、用一个list数组保存上一行的遍历结果
+ * 1、当下一行是头和尾,直接赋值1
+ * 2、当下一行在中间位置j,结果=preItem.get(j - 1) + preItem.get(j)
+ *
+ * 执行用时 :1 ms, 在所有 java 提交中击败了98.18%的用户
+ * 内存消耗 :34.5 MB, 在所有 java 提交中击败了25.70%的用户
+ * @param numRows
+ * @return
+ */
+ public List
> generate(int numRows) {
+ List
> retList = new ArrayList<>();
+ List
> partition(String s) {
+ List
> retList = new ArrayList<>();
+ dfs(retList,new ArrayList<>(),s,0);
+ return retList;
+ }
+
+ private void dfs(List
> retList, List