总览

思考题:如何用代码实现针对代码计算其时间复杂度?

需要深入学习的问题

  1. 背包问题

  2. 滑动窗口算法

  3. 马拉车回文判定算法

  4. 树的迭代遍历(不使用递归)

附加题

  1. 将树打印到控制台。

如果问最短,最少,BFS
如果问连通性,静态就是 DFS,BFS,动态就 UF
如果问依赖性就 topo sort
DAG 的问题就 dfs+memo
矩阵和 Array 通常都是 DP
问数量的通常都是 DP
问是否可以,也很有可能 DP
求所有解的,基本 backtracking
排序总是可以想一想的
万事总可以想HashMap
找规律试试Stack

滑动窗口算法

滑动窗口类型的题目经常是用来执行数组或是链表上某个区间(窗口)上的操作。比如找最长的全为1的子数组长度。滑动窗口一般从第一个元素开始,一直往右边一个一个元素挪动。当然了,根据题目要求,我们可能有固定窗口大小的情况,也有窗口的大小变化的情况。

下面是一些我们用来判断我们可能需要上滑动窗口策略的方法:

  • 这个问题的输入是一些线性结构:比如链表呀,数组啊,字符串啊之类的

  • 让你去求最长/最短子字符串或是某些特定的长度要求

经典题目:

Maximum Sum Subarray of Size K (easy)

Smallest Subarray with a given sum (easy)

Longest Substring with K Distinct Characters (medium)

Fruits into Baskets (medium)

No-repeat Substring (hard)

Longest Substring with Same Letters after Replacement (hard)

Longest Subarray with Ones after Replacement (hard)

LeetCode 239. Sliding Window Maximum (hard)

LeetCode 480. Sliding Window Median (hard)

LeetCode 3. Longest Substring Without Repeating Characters (medium)

LeetCode 76. Minimum Window Substring (hard)

LeetCode 395. Longest Substring with At Least K Repeating Characters (medium)

LeetCode 567. Permutation in String (medium)

LeetCode 438. Find All Anagrams in a String (medium)

LeetCode 209. Minimum Size Subarray Sum (medium)

LeetCode 424. Longest Repeating Character Replacement (medium)

LeetCode 1208. Get Equal Substrings Within Budget (medium)

LeetCode 904. Fruit Into Baskets (medium)

LeetCode 978. Longest Turbulent Subarray (medium)

LeetCode 992. Subarrays with K Different Integers (hard)

LeetCode 995. Minimum Number of K Consecutive Bit Flips (hard)

LeetCode 1040. Moving Stones Until Consecutive II (medium)

LeetCode 1052. Grumpy Bookstore Owner (medium)

LeetCode 1074. Number of Submatrices That Sum to Target (hard)

整体思路

滑动窗口算法的抽象思想:

int left = 0, right = 0;

while (right < s.size()) {
window.add(s[right]);
right++;

    while (valid) {
        window.remove(s[left]);
        left++;
    }
}

其中 window 的数据类型可以视具体情况而定,比如上述题目都使用哈希表充当计数器,当然你也可以用一个数组实现同样效果,因为我们只处理英文字母。

稍微麻烦的地方就是这个 valid 条件,为了实现这个条件的实时更新,我们可能会写很多代码。比如前两道题,看起来解法篇幅那么长,实际上思想还是很简单,只是大多数代码都在处理这个问题而已。

Two Pointer

  1. 76. Minimum Window Substring

  2. 209. Minimum Size Subarray Sum

  3. 239. Sliding Window Maximum

  4. 424. Longest Repeating Character Replacement

  5. 438. Find All Anagrams in a String

  6. 567. Permutation in String

  7. 713. Subarray Product Less Than K

  8. 763. Partition Labels

Pair with Target Sum (easy) Remove Duplicates (easy) Squaring a Sorted Array (easy) Triplet Sum to Zero (medium) Triplet Sum Close to Target (medium) Triplets with Smaller Sum (medium) Subarrays with Product Less than a Target (medium) Dutch National Flag Problem (medium)

双指针是这样的模式:两个指针朝着左右方向移动(双指针分为同向双指针和异向双指针),直到他们有一个或是两个都满足某种条件。双指针通常用在排好序的数组或是链表中寻找对子。比如,你需要去比较数组中每个元素和其他元素的关系时,你就需要用到双指针了。

我们需要双指针的原因是:如果你只用一个指针的话,你得来回跑才能在数组中找到你需要的答案。这一个指针来来回回的过程就很耗时和浪费空间了 — 这是考虑算法的复杂度分析的时候的重要概念。虽然brute force一个指针的解法可能会奏效,但时间复杂度一般会是O(n²)。在很多情况下,双指针能帮助我们找到空间或是时间复杂度更低的解。

识别使用双指针的招数:

  • 一般来说,数组或是链表是排好序的,你得在里头找一些组合满足某种限制条件

  • 这种组合可能是一对数,三个数,或是一个子数组

经典题目:

Pair with Target Sum (easy)

Remove Duplicates (easy)

Squaring a Sorted Array (easy)

Triplet Sum to Zero (medium)

Triplet Sum Close to Target (medium)

Triplets with Smaller Sum (medium)

Subarrays with Product Less than a Target (medium)

Dutch National Flag Problem (medium)

LeetCode 32. Longest Valid Parentheses (hard)

LeetCode 76. Minimum Window Substring (hard)

LeetCode 799. Champagne Tower (medium)

LeetCode 962. Maximum Width Ramp (medium)

LeetCode 1124. Longest Well-Performing Interval (medium)

Fast & Slow pointers, 快慢指针类型

这种模式,有一个非常出门的名字,叫龟兔赛跑。咱们肯定都知道龟兔赛跑啦。但还是再解释一下快慢指针:这种算法的两个指针的在数组上(或是链表上,序列上)的移动速度不一样。还别说,这种方法在解决有环的链表和数组时特别有用。

通过控制指针不同的移动速度(比如在环形链表上),这种算法证明了他们肯定会相遇的。快的一个指针肯定会追上慢的一个(可以想象成跑道上面跑得快的人套圈跑得慢的人)。

咋知道需要用快慢指针模式勒?

  • 问题需要处理环上的问题,比如环形链表和环形数组

  • 当你需要知道链表的长度或是某个特别位置的信息的时候

那啥时候用快慢指针而不是上面的双指针呢?

  • 有些情形下,咱们不应该用双指针,比如我们在单链表上不能往回移动的时候。一个典型的需要用到快慢指针的模式的是当你需要去判断一个链表是否是回文的时候。

LinkedList Cycle (easy)

Start of LinkedList Cycle (medium)

Happy Number (medium)

Middle of the LinkedList (easy)

Merge Intervals,区间合并类型

区间合并模式是一个用来处理有区间重叠的很高效的技术。在设计到区间的很多问题中,通常咱们需要要么判断是否有重叠,要么合并区间,如果他们重叠的话。这个模式是这么起作用的:

给两个区间,一个是a,另外一个是b。别小看就两个区间,他们之间的关系能跑出来6种情况。详细的就看图啦。

怎么识别啥时候用合并区间模式呀?

  • 当你需要产生一堆相互之间没有交集的区间的时候

  • 当你听到重叠区间的时候

Merge Intervals (medium)

Insert Interval (medium)

Intervals Intersection (medium)

Conflicting Appointments (medium)

Cyclic Sort,循环排序

这种模式讲述的是一直很好玩的方法:可以用来处理数组中的数值限定在一定的区间的问题。这种模式一个个遍历数组中的元素,如果当前这个数它不在其应该在的位置的话,咱们就把它和它应该在的那个位置上的数交换一下。你可以尝试将该数放到其正确的位置上,但这复杂度就会是O(n2)。这样的话,可能就不是最优解了。因此循环排序的优势就体现出来了。

咋鉴别这种模式?

  • 这些问题一般设计到排序好的数组,而且数值一般满足于一定的区间

  • 如果问题让你需要在排好序/翻转过的数组中,寻找丢失的/重复的/最小的元素

Cyclic Sort (easy)

Find the Missing Number (easy)

Find all Missing Numbers (easy)

Find the Duplicate Number (easy)

Find all Duplicate Numbers (easy)

In-place Reversal of a LinkedList,链表翻转

在众多问题中,题目可能需要你去翻转链表中某一段的节点。通常,要求都是你得原地翻转,就是重复使用这些已经建好的节点,而不使用额外的空间。这个时候,原地翻转模式就要发挥威力了。

这种模式每次就翻转一个节点。一般需要用到多个变量,一个变量指向头结点(下图中的current),另外一个(previous)则指向咱们刚刚处理完的那个节点。在这种固定步长的方式下,你需要先将当前节点(current)指向前一个节点(previous),再移动到下一个。同时,你需要将previous总是更新到你刚刚新鲜处理完的节点,以保证正确性。

咱们怎么去甄别这种模式呢?

  • 如果你被问到需要去翻转链表,要求不能使用额外空间的时候

经典题目:

Reverse a LinkedList (easy)

Reverse a Sub-list (medium)

Reverse every K-element Sub-list (medium)

Tree Breadth First Search,树上的BFS

这种模式基于宽搜(Breadth First Search (BFS)),适用于需要遍历一颗树。借助于队列数据结构,从而能保证树的节点按照他们的层数打印出来。打印完当前层所有元素,才能执行到下一层。所有这种需要遍历树且需要一层一层遍历的问题,都能用这种模式高效解决。

这种树上的BFS模式是通过把根节点加到队列中,然后不断遍历直到队列为空。每一次循环中,我们都会把队头结点拿出来(remove),然后对其进行必要的操作。在删除每个节点的同时,其孩子节点,都会被加到队列中。

识别树上的BFS模式:

  • 如果你被问到去遍历树,需要按层操作的方式(也称作层序遍历)

经典题目:

Binary Tree Level Order Traversal (easy)

Reverse Level Order Traversal (easy)

Zigzag Traversal (medium)

Level Averages in a Binary Tree (easy)

Minimum Depth of a Binary Tree (easy)

Level Order Successor (easy)

Connect Level Order Siblings (medium)

Tree Depth First Search,树上的DFS

树形DFS基于深搜(Depth First Search (DFS))技术来实现树的遍历。

咱们可以用递归(或是显示栈,如果你想用迭代方式的话)来记录遍历过程中访问过的父节点。

该模式的运行方式是从根节点开始,如果该节点不是叶子节点,我们需要干三件事:

  1. 需要区别我们是先处理根节点(pre-order,前序),处理孩子节点之间处理根节点(in-order,中序),还是处理完所有孩子再处理根节点(post-order,后序)。

  2. 递归处理当前节点的左右孩子。

识别树形DFS:

  • 你需要按前中后序的DFS方式遍历树

  • 如果该问题的解一般离叶子节点比较近。

经典题目:

Binary Tree Path Sum (easy)

All Paths for a Sum (medium)

Sum of Path Numbers (medium)

Path With Given Sequence (medium)

Count Paths for a Sum (medium)

Two Heaps,双堆类型

很多问题中,我们被告知,我们拿到一大把可以分成两队的数字。为了解决这个问题,我们感兴趣的是,怎么把数字分成两半?使得:小的数字都放在一起,大的放在另外一半。双堆模式就能高效解决此类问题。

正如名字所示,该模式用到了两个堆,是不是很难猜?一个最小堆用来找最小元素;一个最大堆,拿到最大元素。这种模式将一半的元素放在最大堆中,这样你可以从这一堆中秒找到最大元素。同理,把剩下一半丢到最小堆中,O(1)时间找到他们中的最小元素。通过这样的方式,这一大堆元素的中位数就可以从两个堆的堆顶拿到数字,从而计算出来。

判断双堆模式的秘诀:

  • 这种模式在优先队列,计划安排问题(Scheduling)中有奇效

  • 如果问题让你找一组数中的最大/最小/中位数

  • 有时候,这种模式在涉及到二叉树数据结构时也特别有用

经典题目:

Find the Median of a Number Stream (medium)

Sliding Window Median (hard)

Maximize Capital (hard)

Subsets,子集类型,一般都是使用多重DFS

超级多的编程面试问题都会涉及到排列和组合问题。子集问题模式讲的是用BFS来处理这些问题。

这个模式是这样的:

给一组数字 [1, 5, 3]

  1. 我们从空集开始:[[]]

  2. 把第一个数(1),加到之前已经存在的集合中:[[], [1]];

  3. 把第二个数(5),加到之前的集合中得到:[[], [1], [5], [1,5]];

  4. 再加第三个数(3),则有:[[], [1], [5], [1,5], [3], [1,3], [5,3], [1,5,3]].

如果判断这种子集模式:

  • 问题需要咱们去找数字的组合或是排列

经典题目:

Subsets (easy)

Subsets With Duplicates (easy)

Permutations (medium)

String Permutations by changing case (medium)

Balanced Parentheses (hard)

Unique Generalized Abbreviations (hard)

Modified Binary Search,改造过的二分

当你需要解决的问题的输入是排好序的数组,链表,或是排好序的矩阵,要求咱们寻找某些特定元素。这个时候的不二选择就是二分搜索。这种模式是一种超级牛的用二分来解决问题的方式。

对于一组满足上升排列的数集来说,这种模式的步骤是这样的:

  1. 首先,算出左右端点的中点。最简单的方式是这样的:middle = (start + end) / 2。但这种计算方式有不小的概率会出现整数越界。因此一般都推荐另外这种写法:middle = start + (end — start) / 2

  2. 如果要找的目标改好和中点所在的数值相等,我们返回中点的下标就行

  3. 如果目标不等的话:我们就有两种移动方式了如果目标比中点在的值小(key < arr[middle]):将下一步搜索空间放到左边(end = middle - 1)

  4. 如果比中点的值大,则继续在右边搜索,丢弃左边:left = middle + 1

经典题目:

Order-agnostic Binary Search (easy)

Ceiling of a Number (medium)

Next Letter (medium)

Number Range (medium)

Search in a Sorted Infinite Array (medium)

Minimum Difference Element (medium)

Bitonic Array Maximum (easy)

Top ‘K’ Elements,前K个系列

任何让我们求解最大/最小/最频繁的K个元素的题,都遵循这种模式。

用来记录这种前K类型的最佳数据结构就是堆了(译者注:在Java中,改了个名,叫优先队列(PriorityQueue))。这种模式借助堆来解决很多这种前K个数值的问题。

这个模式是这样的:

  1. 根据题目要求,将K个元素插入到最小堆或是最大堆。

  2. 遍历剩下的还没访问的元素,如果当前出来到的这个元素比堆顶元素大,那咱们把堆顶元素先删除,再加当前元素进去。

注意这种模式下,咱们不需要去排序数组,因为堆具有这种良好的局部有序性,这对咱们需要解决问题就够了。

识别最大K个元素模式:

  • 如果你需要求最大/最小/最频繁的前K个元素

  • 如果你需要通过排序去找一个特定的数

经典题目:

Top ‘K’ Numbers (easy)

Kth Smallest Number (easy)

‘K’ Closest Points to the Origin (easy)

Connect Ropes (easy)

Top ‘K’ Frequent Numbers (medium)

Frequency Sort (medium)

Kth Largest Number in a Stream (medium)

‘K’ Closest Numbers (medium)

Maximum Distinct Elements (medium)

Sum of Elements (medium)

Rearrange String (hard)

K-way merge,多路归并

K路归并能帮咱们解决那些涉及到多组排好序的数组的问题。

每当你的输入是K个排好序的数组,你就可以用堆来高效顺序遍历其中所有数组的所有元素。你可以将每个数组中最小的一个元素加入到最小堆中,从而得到全局最小值。当我们拿到这个全局最小值之后,再从该元素所在的数组里取出其后面紧挨着的元素,加入堆。如此往复直到处理完所有的元素。

该模式是这样的运行的:

  1. 把每个数组中的第一个元素都加入最小堆中

  2. 取出堆顶元素(全局最小),将该元素放入排好序的结果集合里面

  3. 将刚取出的元素所在的数组里面的下一个元素加入堆

  4. 重复步骤2,3,直到处理完所有数字

识别K路归并:

  • 该问题的输入是排好序的数组,链表或是矩阵

  • 如果问题让咱们合并多个排好序的集合,或是需要找这些集合中最小的元素

经典题目:

Merge K Sorted Lists (medium)

Kth Smallest Number in M Sorted Lists (Medium)

Kth Smallest Number in a Sorted Matrix (Hard)

Smallest Number Range (Hard)

Topological Sort (Graph),拓扑排序类型

拓扑排序模式用来寻找一种线性的顺序,这些元素之间具有依懒性。比如,如果事件B依赖于事件A,那A在拓扑排序顺序中排在B的前面。

这种模式定义了一种简单方式来理解拓扑排序这种技术。

这种模式是这样奏效的:

  1. 初始化

    1. 借助于HashMap将图保存成邻接表形式。

    2. 找到所有的起点,用HashMap来帮助记录每个节点的入度

  2. 创建图,找到每个节点的入度

    1. 利用输入,把图建好,然后遍历一下图,将入度信息记录在HashMap中

  3. 找所有的起点

    1. 所有入度为0的节点,都是有效的起点,而且我们讲他们都加入到一个队列中

  4. 排序

    1. 对每个起点,执行以下步骤

      1. 把它加到结果的顺序中

      2. 将其在图中的孩子节点取到

      3. 将其孩子的入度减少1

      4. 如果孩子的入度变为0,则改孩子节点成为起点,将其加入队列中

    2. 重复(a)过程,直到起点队列为空。

拓扑排序模式识别:

  • 待解决的问题需要处理无环图

  • 你需要以一种有序的秩序更新输入元素

  • 需要处理的输入遵循某种特定的顺序

经典题目:

Topological Sort (medium)

Tasks Scheduling (medium)

Tasks Scheduling Order (medium)

All Tasks Scheduling Orders (hard)

Alien Dictionary (hard)

Backtrack,回溯

参考 46. Permutations 认真学习一下回溯思想。

玩回溯,一定要画出递归调用树。

回溯优化,重要的是,要学会剪枝!

附加题

  1. 写程序尝试生成递归调用树。

Greedy,贪心

Brute Force,暴力破解

选择排序,冒泡排序,在有序数组中的顺序查找等等都属于暴力破解的解法。

Decrease and Conquer,减治法

Divide and Conquer,分治法

Transform and Conquer,变知法

Dynamic Programming,动态规划

0/1 Knapsack,0/1背包

0/1 Knapsack,0/1背包问题

Equal Subset Sum Partition,相等子集划分问题

Subset Sum,子集和问题

Minimum Subset Sum Difference,子集和的最小差问题

Count of Subset Sum,相等子集和的个数问题

Target Sum,寻找目标和的问题

Unbounded Knapsack,无限背包

Unbounded Knapsack,无限背包

Rod Cutting,切钢条问题

Coin Change,换硬币问题

Minimum Coin Change,凑齐每个数需要的最少硬币问题

Maximum Ribbon Cut,丝带的最大值切法

Fibonacci Numbers,斐波那契数列

Fibonacci numbers,斐波那契数列问题

Staircase,爬楼梯问题

Number factors,分解因子问题

Minimum jumps to reach the end,蛙跳最小步数问题

Minimum jumps with fee,蛙跳带有代价的问题

House thief,偷房子问题

Palindromic Subsequence,回文子系列

Longest Palindromic Subsequence,最长回文子序列

Longest Palindromic Substring,最长回文子字符串

Count of Palindromic Substrings,最长子字符串的个数问题

Minimum Deletions in a String to make it a Palindrome,怎么删掉最少字符构成回文

Palindromic Partitioning,怎么分配字符,形成回文

Longest Common Substring,最长子字符串系列

Longest Common Substring,最长相同子串

Longest Common Subsequence,最长相同子序列

Minimum Deletions & Insertions to Transform a String into another,字符串变换

Longest Increasing Subsequence,最长上升子序列

Maximum Sum Increasing Subsequence,最长上升子序列和

Shortest Common Super-sequence,最短超级子序列

Minimum Deletions to Make a Sequence Sorted,最少删除变换出子序列

Longest Repeating Subsequence,最长重复子序列

Subsequence Pattern Matching,子序列匹配

Longest Bitonic Subsequence,最长字节子序列

Longest Alternating Subsequence,最长交差变换子序列

Edit Distance,编辑距离

Strings Interleaving,交织字符串

1. Two Sum

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].
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.diguage.algorithm.leetcode;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * = 1. Two Sum
 *
 * https://leetcode.com/problems/two-sum/description/[Two Sum - LeetCode]
 *
 * 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:
 * [source]
 * ----
 * Given nums = [2, 7, 11, 15], target = 9,
 *
 * Because nums[0] + nums[1] = 2 + 7 = 9,
 * return [0, 1].
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-06-30
 */
public class _0001_TwoSum {
    /**
     * 原始算法,时间复杂度为 `O(n^2^)`.
     *
     * @param nums   数组
     * @param target 目标
     * @return 结果
     */
    public static int[] twoSum(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return null;
        }
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] == target) {
                    return new int[]{i, j};
                }
            }
        }

        return null;
    }

    /**
     * 优化后的算法,时间复杂度减低为 `O(n)`, 空间复杂度提高了。
     *
     * @param nums   数组
     * @param target 目标
     * @return 结果
     */
    public static int[] twoSumO1(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return null;
        }

        Map<Integer, Integer> diffNumToIndexMap = new HashMap<>(nums.length * 4 / 3);
        for (int i = 0; i < nums.length; i++) {
            if (diffNumToIndexMap.containsKey(nums[i])) {
                return new int[]{diffNumToIndexMap.get(nums[i]), i};
            } else {
                diffNumToIndexMap.put(target - nums[i], i);
            }
        }

        return null;
    }

    public static void main(String[] args) {
        int[] nums = new int[]{4, 9, 2, 7, 11, 15};
        int target = 8;
        System.out.println(Arrays.toString(twoSumO1(nums, target)));
    }
}

2. Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package com.diguage.algorithm.leetcode;

import com.diguage.algorithm.util.ListNode;
import com.diguage.algorithm.util.ListNodeUtils;

import java.util.Arrays;
import java.util.Objects;

import static com.diguage.algorithm.util.ListNodeUtils.printListNode;

/**
 * = 2. Add Two Numbers
 *
 * https://leetcode.com/problems/add-two-numbers/description/[Add Two Numbers - LeetCode]
 *
 * You are given two non-empty linked lists representing two non-negative
 * integers. The digits are stored in reverse order and each of their nodes
 * contain a single digit. Add the two numbers and return it as a linked list.
 *
 * You may assume the two numbers do not contain any leading zero, except the number 0 itself.
 *
 * .Example:
 * [source]
 * ----
 * Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
 * Output: 7 -> 0 -> 8
 * Explanation: 342 + 465 = 807.
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-09-17 11:42
 */
public class _0002_AddTwoNumbers {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//        ListNode h1 = l1;
//        ListNode h2 = l2;
//        ListNode mergeList = null;
//        int carryOver = 0;
//        while (Objects.nonNull(h1) && Objects.nonNull(h2)) {
//            int v1 = h1.val;
//            int v2 = h2.val;
//            int newVal = v1 + v2 + carryOver;
//            if (newVal >= 10) {
//                carryOver = 1;
//                newVal -= 10;
//            } else {
//                carryOver = 0;
//            }
//            ListNode listNode = new ListNode(newVal);
//            listNode.next = mergeList;
//            mergeList = listNode;
//            h1 = h1.next;
//            h2 = h2.next;
//        }
//
//        ListNode rest = null;
//        if (Objects.nonNull(h1)) {
//            rest = h1;
//        }
//        if (Objects.nonNull(h2)) {
//            rest = h2;
//        }
//
//        ListNode restHead = rest;
//        while (Objects.nonNull(rest) && carryOver > 0) {
//            int newVal = rest.val + carryOver;
//            if (newVal >= 10) {
//                carryOver = 1;
//                newVal -= 10;
//            } else {
//                carryOver = 0;
//            }
//            rest.val = newVal;
//            if (Objects.isNull(rest.next) && carryOver > 0) {
//                ListNode carryNode = new ListNode(carryOver);
//                rest.next = carryNode;
//                carryOver = 0;
//            }
//            rest = rest.next;
//        }
//        if (Objects.isNull(restHead) && carryOver > 0) {
//            restHead = new ListNode(carryOver);
//        }
//
//        while (Objects.nonNull(mergeList)) {
//            ListNode next = mergeList.next;
//            mergeList.next = restHead;
//            restHead = mergeList;
//            mergeList = next;
//        }
//
//        return restHead;
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
        ListNode result = l1;
        int digit = 0;
        while (Objects.nonNull(l1.next) && Objects.nonNull(l2.next)) {
            int sum = l1.val + l2.val + digit;
            l1.val = sum % 10;
            digit = sum / 10;
            l1 = l1.next;
            l2 = l2.next;
        }
        int sum = l1.val + l2.val + digit;
        l1.val = sum % 10;
        digit = sum / 10;
        if (Objects.isNull(l1.next) && Objects.nonNull(l2.next)) {
            l1.next = l2.next;
            l1 = l1.next;
        }
        ListNode tail = null;
        ;
        while (digit > 0 && Objects.nonNull(l1)) {
            tail = l1;
            sum = l1.val + digit;
            l1.val = sum % 10;
            digit = sum / 10;
            l1 = l1.next;
        }
        if (digit > 0) {
            tail.next = new ListNode(digit);
        }
        return result;
//        ListNode result = l1;
//        int digit = 0;
//        while (Objects.nonNull(l1.next) && Objects.nonNull(l2.next)) {
//            int sum = l1.val + l2.val + digit;
//            l1.val = sum % 10;
//            digit = sum / 10;
//            l1 = l1.next;
//            l2 = l2.next;
//        }
//        int sum = l1.val + l2.val + digit;
//        l1.val = sum % 10;
//        digit = sum / 10;
//        if (Objects.isNull(l1.next) && Objects.nonNull(l2.next)) {
//            l1.next = l2.next;
//            l1 = l1.next;
//        }
//        while (digit > 0 && Objects.nonNull(l1.next)) {
//            sum = l1.val + digit;
//            l1.val = sum % 10;
//            digit = sum / 10;
//            l1 = l1.next;
//        }
//        if (digit > 0) {
//            l1.next = new ListNode(digit);
//        }
//        return result;
    }


    public static void main(String[] args) {
        _0002_AddTwoNumbers result = new _0002_AddTwoNumbers();
//        ListNode list1 = result.convertNumberToList(1);
//        ListNode list2 = result.convertNumberToList(99);
//        ListNode sum = result.addTwoNumbers(list1, list2);
//        printListNode(sum);
        ListNode list = result.addTwoNumbers(ListNodeUtils.build(Arrays.asList(9, 8)), ListNodeUtils.build(Arrays.asList(8)));
        ListNodeUtils.printListNode(list);
    }


    public ListNode convertNumberToList(int number) {
        ListNode result = null;
        for (int i = number; i > 0; i /= 10) {
            int vaule = i % 10;
            ListNode listNode = new ListNode(vaule);
            if (Objects.isNull(result)) {
                result = listNode;
            } else {
                ListNode last = result;
                while (Objects.nonNull(last.next)) {
                    last = last.next;
                }
                last.next = listNode;
            }
        }
        return result;
    }
}

3. Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.

Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:
Input: "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
             Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package com.diguage.algorithm.leetcode;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * = 3. Longest Substring Without Repeating Characters
 *
 * https://leetcode.com/problems/longest-substring-without-repeating-characters/[Longest Substring Without Repeating Characters - LeetCode]
 *
 * Given a string, find the length of the *longest substring* without repeating characters.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: "abcabcbb"
 * Output: 3
 * Explanation: The answer is "abc", with the length of 3.
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: "bbbbb"
 * Output: 1
 * Explanation: The answer is "b", with the length of 1.
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: "pwwkew"
 * Output: 3
 * Explanation: The answer is "wke", with the length of 3.
 * Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-11 21:31
 */
public class _0003_LongestSubstringWithoutRepeatingCharacters {
  /**
   * Runtime: 6 ms, faster than 85.45% of Java online submissions for Longest Substring Without Repeating Characters.
   *
   * Memory Usage: 36.4 MB, less than 99.80% of Java online submissions for Longest Substring Without Repeating Characters.
   */
  public int lengthOfLongestSubstring(String s) {
    if (Objects.isNull(s) || s.length() == 0) {
      return 0;
    }
    int result = 0;
    int length = s.length();
    Map<Character, Integer> charToIndexMap = new HashMap<>(length * 4 / 3);
    for (int i = 0, j = 0; j < length; j++) {
      char aChar = s.charAt(j);
      if (charToIndexMap.containsKey(aChar)) {
        // 这里,如果存在重复的,则从上一个重复字符的下一个字符开始计算。
        Integer index = charToIndexMap.get(aChar);
        if (index + 1 > i) {
          i = index + 1;
        }
      }
      charToIndexMap.put(aChar, j);
      if (j - i + 1 > result) {
        result = j - i + 1;
      }

    }
    return result;
  }

  /**
   * Runtime: 9 ms, faster than 49.55% of Java online submissions for Longest Substring Without Repeating Characters.
   *
   * Memory Usage: 36 MB, less than 99.88% of Java online submissions for Longest Substring Without Repeating Characters.
   */
  public int lengthOfLongestSubstringWithSlidingWindow(String s) {
    if (Objects.isNull(s) || s.length() == 0) {
      return 0;
    }
    int result = 0;
    int length = s.length();
    int head = 0;
    int tail = 0;
    Set<Character> characters = new HashSet<>(length * 4 / 3);
    while (head < length && tail < length) {
      if (!characters.contains(s.charAt(tail))) {
        characters.add(s.charAt(tail));
        tail++;
        if (result < tail - head) {
          result = tail - head;
        }
      } else {
        characters.remove(s.charAt(head));
        head++;
      }
    }
    return result;
  }

  /**
   * Runtime: 221 ms, faster than 5.02% of Java online submissions for Longest Substring Without Repeating Characters.
   *
   * Memory Usage: 37.3 MB, less than 97.43% of Java online submissions for Longest Substring Without Repeating Characters.
   */
  public int lengthOfLongestSubstringWithBruteForce(String s) {
    if (Objects.isNull(s) || s.length() == 0) {
      return 0;
    }
    char[] chars = s.toCharArray();
    int result = 0;
    for (int i = 0; i < chars.length; i++) {
      Set<Character> characters = new HashSet<>(chars.length * 4 / 3);
      for (int j = i; j < chars.length; j++) {
        char aChar = chars[j];
        if (characters.contains(aChar)) {
          break;
        } else {
          characters.add(aChar);
        }
      }
      if (characters.size() > result) {
        result = characters.size();
      }
    }
    return result;
  }

  public static void main(String[] args) {
    _0003_LongestSubstringWithoutRepeatingCharacters result = new _0003_LongestSubstringWithoutRepeatingCharacters();
    System.out.println("2 - " + result.lengthOfLongestSubstring("aab"));
    System.out.println("3 - " + result.lengthOfLongestSubstring("abcabcbb"));
    System.out.println("1 - " + result.lengthOfLongestSubstring("bbbbb"));
    System.out.println("3 - " + result.lengthOfLongestSubstring("pwwkew"));
  }
}

4. Median of Two Sorted Arrays

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:
nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
package com.diguage.algorithm.leetcode;

/**
 * = 4. Median of Two Sorted Arrays
 *
 * https://leetcode.com/problems/median-of-two-sorted-arrays/description/[Median of Two Sorted Arrays - LeetCode]
 *
 * There are two sorted arrays nums1 and nums2 of size m and n respectively.
 *
 * Find the median of the two sorted arrays. The overall run time complexity
 * should be latexmath:[O(log(m+n))].
 *
 * .Example 1:
 * [source]
 * ----
 * nums1 = [1, 3]
 * nums2 = [2]
 *
 * The median is 2.0
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * nums1 = [1, 2]
 * nums2 = [3, 4]
 *
 * The median is (2 + 3)/2 = 2.5
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-01
 */
public class _0004_MedianOfTwoSortedArrays {
    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (isEmpty(nums1) && isEmpty(nums2)) {
            return 0;
        }
        if (isEmpty(nums1)) {
            return singleArray(nums2);
        }
        if (isEmpty(nums2)) {
            return singleArray(nums1);
        }

        int length = nums1.length + nums2.length;
        boolean isOdd = (length & 1) == 1;
        int i1 = 0;
        int i2 = 0;
        int min = nums1[0] < nums2[0] ? nums1[0] : nums2[0];
        int temp = min;
        int last = min;
        int now = min;
        for (int i = 0; i < length; i++) {
            if (i1 < nums1.length && i2 < nums2.length) {
                if (nums1[i1] <= nums2[i2]) {
                    temp = nums1[i1];
                    i1++;
                } else {
                    temp = nums2[i2];
                    i2++;
                }
            } else if (i1 < nums1.length) {
                temp = nums1[i1];
                i1++;
            } else {
                temp = nums2[i2];
                i2++;
            }

            if (i > 0) {
                last = now;
                now = temp;
            }

            if (length / 2 == i) {
                if (isOdd) {
                    return now;
                } else {
                    return ((double) (last + now)) / 2.0;
                }
            }
        }
        return 0;
    }

    private static boolean isEmpty(int[] nums) {
        return nums == null || nums.length == 0;
    }

    public static double findMedianSortedArraysBest(int[] nums1, int[] nums2) {
        // TODO
        return 0;
    }

    private static double singleArray(int[] nums2) {
        boolean isOdd = (nums2.length & 1) == 1;
        if (isOdd) {
            return nums2[nums2.length / 2];
        } else {
            return (nums2[nums2.length / 2 - 1] + nums2[nums2.length / 2]) / 2.0;
        }
    }

    public static void main(String[] args) {
        int[] nums1 = new int[]{100001};
        int[] nums2 = new int[]{100000};

        System.out.println(findMedianSortedArrays(nums1, nums2));
    }
}

5. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd"
Output: "bb"

解题分析

最简单的方式:使用两个指针,把字符串逐个"拆成"子串,然后留下最大子串即可。可惜,这种算法的时间复杂度是 O(n3)。

没想到,竟然存在时间复杂度为 O(n) 的算法:Manacher’s Algorithm。在维基百科上有解释: Longest palindromic substring - Wikipedia。回头研究研究再补充!

另外,这道题还可以练手动态规划。

参考资料

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 5. Longest Palindromic Substring
 *
 * https://leetcode.com/problems/longest-palindromic-substring/[Longest Palindromic Substring - LeetCode]
 *
 * Given a string s, find the longest palindromic substring in s.
 * You may assume that the maximum length of s is 1000.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: "babad"
 * Output: "bab"
 * Note: "aba" is also a valid answer.
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: "cbbd"
 * Output: "bb"
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-13 11:12
 */
public class _0005_LongestPalindromicSubstring {
  /**
   * Runtime: 1118 ms, faster than 5.01% of Java online submissions for Longest Palindromic Substring.
   *
   * Memory Usage: 37.2 MB, less than 94.36% of Java online submissions for Longest Palindromic Substring.
   */
  public String longestPalindromeBruteForce(String s) {
    if (Objects.isNull(s) || s.length() == 1) {
      return s;
    }
    int maxLength = 1;
    int begin = 0;
    for (int i = 0; i < s.length() - 1; i++) {
      for (int j = i + 1; j < s.length(); j++) {
        // 这里要注意:先判断长度,然后执行回文判断,相当于做了剪枝操作,效率会提高很多。
        if (j - i + 1 > maxLength && isPalindrome(s, i, j)) {
          maxLength = j - i + 1;
          begin = i;
        }
      }
    }
    return s.substring(begin, begin + maxLength);
  }

  private boolean isPalindrome(String s, int low, int high) {
    while (low <= high) {
      if (s.charAt(low) != s.charAt(high)) {
        return false;
      }
      low++;
      high--;
    }
    return true;
  }

  public String longestPalindrome(String s) {
    if (Objects.isNull(s) || s.length() <= 1) {
      return s;
    }
    int start = 0;
    int end = 0;
    for (int i = 0; i < s.length() - 1; i++) {
      int len1 = expandAroundCenter(s, i, i);
      int len2 = expandAroundCenter(s, i, i + 1);
      int len = Math.max(len1, len2);
      if (len > end - start) {
        start = i - (len - 1) / 2;
        end = i + len / 2;
      }
    }
    return s.substring(start, end + 1);
  }

  private int expandAroundCenter(String s, int left, int right) {
    while (0 <= left && right < s.length() && s.charAt(left) == s.charAt(right)) {
      left--;
      right++;
    }
    return right - left - 1;
  }

  public static void main(String[] args) {
    _0005_LongestPalindromicSubstring solution = new _0005_LongestPalindromicSubstring();
    System.out.println("aaabaaa - " + solution.longestPalindrome("cbbd"));
    System.out.println("aaabaaa - " + solution.longestPalindrome("aaabaaaa"));
    System.out.println("ccc - " + solution.longestPalindrome("ccc"));
    System.out.println("a - " + solution.longestPalindrome("abcda"));
    System.out.println("abcba - " + solution.longestPalindrome("abcba"));
    System.out.println("a - " + solution.longestPalindrome("ac"));
    System.out.println("bab - " + solution.longestPalindrome("babad"));
    System.out.println("bb  - " + solution.longestPalindrome("cbbd"));
    System.out.println("bb  - " + solution.longestPalindrome("abbc"));
    System.out.println("a - " + solution.longestPalindrome("a"));
  }
}

6. ZigZag Conversion

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

P   A   H   N
A P L S I I G
Y   I   R

And then read line by line: "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:

string convert(string s, int numRows);
Example 1:
Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"
Example 2:
Input: s = "PAYPALISHIRING", numRows = 4
Output: "PINALSIGYAHRPI"
Explanation:

P     I    N
A   L S  I G
Y A   H R
P     I
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 6. ZigZag Conversion
 *
 * https://leetcode.com/problems/zigzag-conversion/[ZigZag Conversion - LeetCode]
 *
 * The string `"PAYPALISHIRING"` is written in a zigzag pattern on a given number
 * of rows like this: (you may want to display this pattern in a fixed font for
 * better legibility)
 *
 * [source]
 * ----
 * P   A   H   N
 * A P L S I I G
 * Y   I   R
 * ----
 *
 * And then read line by line: `"PAHNAPLSIIGYIR"`
 *
 * Write the code that will take a string and make this conversion given a number of rows:
 *
 * [source]
 * ----
 * string convert(string s, int numRows);
 * ----
 *
 * .Example 1:
 * [source]
 * ----
 * Input: s = "PAYPALISHIRING", numRows = 3
 * Output: "PAHNAPLSIIGYIR"
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: s = "PAYPALISHIRING", numRows = 4
 * Output: "PINALSIGYAHRPI"
 * Explanation:
 *
 * P     I    N
 * A   L S  I G
 * Y A   H R
 * P     I
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-14 18:20
 */
public class _0006_ZigZagConversion {
    /**
     * Runtime: 5 ms, faster than 73.81% of Java online submissions for ZigZag Conversion.
     *
     * Memory Usage: 38.7 MB, less than 77.68% of Java online submissions for ZigZag Conversion.
     */
    public String convert(String s, int numRows) {
        if (Objects.isNull(s) || s.length() == 0) {
            return "";
        }
        if (numRows == 1) {
            return s;
        }
        int length = s.length();
        int columnLength = length / numRows;

        StringBuilder[] builders = new StringBuilder[numRows];
        for (int i = 0; i < builders.length; i++) {
            builders[i] = new StringBuilder(columnLength);
        }

        int direction = 1;
        int selector = 0;
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (selector == 0) {
                direction = 1;
            }
            if (selector == numRows - 1) {
                direction = -1;
            }
            char aChar = chars[i];
            builders[selector].append(aChar);
            selector += direction;
        }

        StringBuilder result = new StringBuilder(length);
        for (StringBuilder builder : builders) {
            result.append(builder);
        }
        return result.toString();
    }

    public static void main(String[] args) {
        _0006_ZigZagConversion solution = new _0006_ZigZagConversion();

        String example3 = solution.convert("AB", 1);
        System.out.println(example3 + " " + "AB".equals(example3));

        String example1 = solution.convert("PAYPALISHIRING", 3);
        System.out.println(example1 + " " + "PAHNAPLSIIGYIR".equals(example1));

        String example2 = solution.convert("PAYPALISHIRING", 4);
        System.out.println(example2 + " " + "PINALSIGYAHRPI".equals(example2));
    }
}

7. Reverse Integer

Given a 32-bit signed integer, reverse digits of an integer.

Example 1:
Input: 123
Output: 321
Example 2:
Input: -123
Output: -321
Example 3:
Input: 120
Output: 21

Note:

Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [-231, 231- 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

解题分析

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package com.diguage.algorithm.leetcode;

import java.util.ArrayList;
import java.util.List;

/**
 * = 7. Reverse Integer
 *
 * https://leetcode.com/problems/reverse-integer/description/[Reverse Integer - LeetCode]
 *
 * Given a 32-bit signed integer, reverse digits of an integer.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: 123
 * Output: 321
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: -123
 * Output: -321
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: 120
 * Output: 21
 * ----
 *
 * == Note
 *
 * Assume we are dealing with an environment which could only store integers
 * within the 32-bit signed integer range: [−231,  231 − 1]. For the purpose of
 * this problem, assume that your function returns 0 when the reversed integer overflows.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-01
 */
public class _0007_ReverseInteger {
  public static int reverse(int x) {
    int sign = 1;
    if (x < 0) {
      sign = -1;
      if (x < -Integer.MAX_VALUE) {
        return 0;
      }
      x = -x;
    }
    int result = 0;
    while (x > 0) {
      int digit = x % 10;
      int num = result * 10 + digit;
      if ((num - digit) / 10 != result) {
        return 0;
      }
      result = num;

      x /= 10;
    }
    return sign * result;
  }

  public static int reverse1(int x) {
    if (x == 0
      || x > Math.pow(2, 31)
      || x < -Math.pow(2, 31)) {
      return 0;
    }

    int sign = 1;
    int positiveNum = x;
    if (x < 0) {
      sign = -1;
      positiveNum = x * sign;
    }

    boolean zeroOfEnd = true;
    List<Integer> bitNums = new ArrayList<>(25);
    for (int i = positiveNum; i > 0; ) {
      int bitNum = i % 10;
      i = i / 10;
      if (zeroOfEnd && bitNum == 0) {
        continue;
      }
      bitNums.add(bitNum);
      if (zeroOfEnd) {
        zeroOfEnd = false;
      }
    }

    long result = 0;
    for (int j = 0; j < bitNums.size(); j++) {
      result += bitNums.get(j) * ((long) Math.pow(10, bitNums.size() - j - 1));
    }
    if (result > Integer.MAX_VALUE) {
      return 0;
    }

    return (int) result * sign;
  }

  public static void main(String[] args) {
    System.out.println(reverse(120));
    System.out.println(reverse(123));
    System.out.println(reverse(-123));
    System.out.println(reverse(-10305));
    int i = 1534236469;
    System.out.println(reverse(i));
    System.out.println(Integer.bitCount(i));
    System.out.println(i);
    System.out.println(reverse(Integer.MAX_VALUE));
    System.out.println(reverse(Integer.MIN_VALUE));
  }
}

8. String to Integer (atoi)

Implement atoi which converts a string to an integer.

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.

The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.

If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.

If no valid conversion could be performed, a zero value is returned.

Note:

  • Only the space character ' ' is considered as whitespace character.

  • Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [-231, 231- 1]. If the numerical value is out of the range of representable values, INT_MAX (231- 1) or INT_MIN (-231) is returned.

Example 1:
Input: "42"
Output: 42
Example 2:
Input: "   -42"
Output: -42
Explanation: The first non-whitespace character is '-', which is the minus sign.
             Then take as many numerical digits as possible, which gets 42.
Example 3:
Input: "4193 with words"
Output: 4193
Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
Example 4:
Input: "words and 987"
Output: 0
Explanation: The first non-whitespace character is 'w', which is not a numerical
             digit or a +/- sign. Therefore no valid conversion could be performed.
Example 5:
Input: "-91283472332"
Output: -2147483648
Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer.
             Thefore INT_MIN (-231) is returned.

解题分析

result > (Integer.MAX_VALUE - num) / 10 注意这个判断移除方法。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 8. String to Integer (atoi)
 *
 * https://leetcode.com/problems/string-to-integer-atoi/[String to Integer (atoi) - LeetCode]
 *
 * Implement atoi which converts a string to an integer.
 *
 * The function first discards as many whitespace characters as necessary until the first
 * non-whitespace character is found. Then, starting from this character, takes an optional
 * initial plus or minus sign followed by as many numerical digits as possible, and interprets
 * them as a numerical value.
 *
 * The string can contain additional characters after those that form the integral number,
 * which are ignored and have no effect on the behavior of this function.
 *
 * If the first sequence of non-whitespace characters in str is not a valid integral number,
 * or if no such sequence exists because either str is empty or it contains only whitespace characters,
 * no conversion is performed.
 *
 * If no valid conversion could be performed, a zero value is returned.
 *
 * Note::
 * * Only the space character `' '` is considered as whitespace character.
 * * Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231,  231 − 1]. If the numerical value is out of the range of representable values, INT_MAX (231 − 1) or INT_MIN (−231) is returned.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: "42"
 * Output: 42
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: "   -42"
 * Output: -42
 * Explanation: The first non-whitespace character is '-', which is the minus sign.
 * Then take as many numerical digits as possible, which gets 42.
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: "4193 with words"
 * Output: 4193
 * Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
 * ----
 *
 * .Example 4:
 * [source]
 * ----
 * Input: "words and 987"
 * Output: 0
 * Explanation: The first non-whitespace character is 'w', which is not a numerical
 * digit or a +/- sign. Therefore no valid conversion could be performed.
 * ----
 *
 * .Example 5:
 * [source]
 * ----
 * Input: "-91283472332"
 * Output: -2147483648
 * Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer.
 * Thefore INT_MIN (−231) is returned.
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-14 19:57
 */
public class _0008_StringToIntegerAtoi {

  public int myAtoi(String str) {
    char[] chars = str.toCharArray();
    int n = str.length();
    int idx = 0;
    // 除去前面的空白符
    while (idx < n && Character.isWhitespace(chars[idx])) {
      idx++;
    }
    if (idx == n) {
      return 0;
    }
    // 判断正负号
    boolean negative = false;
    if (chars[idx] == '-') {
      negative = true;
      idx++;
    } else if (chars[idx] == '+') {
      // negative = false;
      idx++;
    } else if (!Character.isDigit(chars[idx])) {
      return 0;
    }
    // 计算数字
    int result = 0;
    while (idx < n && Character.isDigit(chars[idx])) {
      int num = chars[idx] - '0';
      // 注意这个判断是否溢出的方式。
      if (result > (Integer.MAX_VALUE - num) / 10) {
        return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
      }
      result = result * 10 + num;
      idx++;
    }
    return negative ? -result : result;
  }

  /**
   * Runtime: 1 ms, faster than 100.00% of Java online submissions for String to Integer (atoi).
   *
   * Memory Usage: 35.8 MB, less than 99.90% of Java online submissions for String to Integer (atoi).
   */
  public int myAtoi2(String str) {
    int result = 0;
    if (Objects.isNull(str) || str.length() == 0) {
      return result;
    }

    int index = 0;
    int length = str.length();
    while (index < length && str.charAt(index) == ' ') {
      index++;
    }

    int sign = 1;
    if (index < length && isSign(str.charAt(index))) {
      if (str.charAt(index) == '-') {
        sign = -1;
      }
      index++;
    }

    int decimals = 10;
    while (index < length && isNumber(str.charAt(index))) {
      int number = str.charAt(index) - '0';

      if (result > Integer.MAX_VALUE / 10
        || (result == Integer.MAX_VALUE / 10 && number > Integer.MAX_VALUE % 10)) {
        return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
      }

      result = result * decimals + number;

      index++;
    }

    return result * sign;
  }

  private boolean isNumber(char aChar) {
    return '0' <= aChar && aChar <= '9';
  }

  private boolean isSign(char aChar) {
    return aChar == '-' || aChar == '+';
  }

  public int myAtoiD2u(String str) {
    long result = 0;
    if (Objects.isNull(str) || str.length() == 0) {
      return (int) result;
    }
    char[] chars = str.toCharArray();
    int start = -1;
    int end = -1;
    int signed = 1;
    boolean hasSigned = false;
    boolean isStarted = false;
    boolean firstIsZero = true;
    for (int i = 0; i < chars.length; i++) {
      char aChar = chars[i];
      if (isStarted && !isNumber(aChar)) {
        break;
      }
      if (aChar == ' ') {
        start++;
        continue;
      }
      if (!isNumber(aChar) && !isSign(aChar)) {
        return (int) result;
      }
      if (isSign(aChar) && !hasSigned) {
        if (aChar == '-') {
          signed = -1;
        }
        hasSigned = true;
        isStarted = true;
        continue;
      }
      isStarted = true;
      if (firstIsZero && aChar == '0') {
        continue;
      }
      if (isStarted && !isNumber(aChar)) {
        break;
      }
      if (firstIsZero && aChar != '0' && isNumber(aChar)) {
        firstIsZero = false;
        start = i;
        end = i;
      }
      if (isNumber(aChar)) {
        end = i;
      } else {
        break;
      }
    }

    for (int i = end; chars.length > i && i >= start && start >= 0; i--) {
      char aChar = chars[i];
      long base = pow(10, end - i);
      if (base > Integer.MAX_VALUE) {
        if (signed == 1) {
          return Integer.MAX_VALUE;
        } else {
          return Integer.MIN_VALUE;
        }
      }
      if ('0' == aChar || isSign(aChar)) {
        continue;
      }
      if (!isNumber(aChar)) {
        break;
      }
      long newResult = (long) (aChar - '0') * base + result;
      boolean isOutOfRange = (signed > 0 && newResult > Integer.MAX_VALUE)
        || (signed < 0 && newResult * signed < Integer.MIN_VALUE);
      if (isOutOfRange) {
        if (signed == 1) {
          return Integer.MAX_VALUE;
        } else {
          return Integer.MIN_VALUE;
        }
      }
      result = newResult;
    }

    result *= signed;

    return (int) result;
  }

  private long pow(int base, int exponent) {
    long result = 1L;
    for (int i = 0; i < exponent; i++) {
      result *= base;
    }
    return result;
  }

  public static void main(String[] args) {
    _0008_StringToIntegerAtoi solution = new _0008_StringToIntegerAtoi();

    int i17 = solution.myAtoi("-2147483647");
    System.out.println(i17 + " : " + (-2147483647 == i17));

    int i16 = solution.myAtoi("-2147483649");
    System.out.println(i16 + " : " + (-2147483648 == i16));

    int i15 = solution.myAtoi(Integer.toString(Integer.MIN_VALUE));
    System.out.println(i15 + " : " + (-2147483648 == i15));

    int i14 = solution.myAtoi("2147483646");
    System.out.println(i14 + " : " + (2147483646 == i14));

    int i13 = solution.myAtoi("0-1");
    System.out.println(i13 + " : " + (0 == i13));

    int i12 = solution.myAtoi("    0000000000000   ");
    System.out.println(i12 + " : " + (0 == i12));

    int i11 = solution.myAtoi("  0000000000012345678");
    System.out.println(i11 + " : " + (12345678 == i11));

    int i10 = solution.myAtoi("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000522545459");
    System.out.println(i10 + " : " + (Integer.MAX_VALUE == i10));

    int i9 = solution.myAtoi("-abc");
    System.out.println(i9 + " : " + (0 == i9));

    int i8 = solution.myAtoi("20000000000000000000");
    System.out.println(i8 + " : " + (Integer.MAX_VALUE == i8));

    int i7 = solution.myAtoi("-6147483648");
    System.out.println(i7 + " : " + (Integer.MIN_VALUE == i7));

    int i6 = solution.myAtoi("+");
    System.out.println(i6 + " : " + (0 == i6));

    int i3 = solution.myAtoi("4193 with words");
    System.out.println(i3 + " : " + (4193 == i3));

    int i2 = solution.myAtoi("   -42");
    System.out.println(i2 + " : " + (-42 == i2));

    int i1 = solution.myAtoi("42");
    System.out.println(i1 + " : " + (42 == i1));

    int i4 = solution.myAtoi("words and 987");
    System.out.println(i4 + " : " + (0 == i4));

    int i5 = solution.myAtoi("-91283472332");
    System.out.println(i5 + " : " + (-2147483648 == i5));
  }
}

9. Palindrome Number

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

Example 1:
Input: 121
Output: true
Example 2:
Input: -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
Example 3:
Input: 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.

Follow up:

Coud you solve it without converting the integer to a string?

解题分析

如果是回文数字,则反转之后数字相等。可以再进一步,不需要完全反转,只需要反转一半即可,反转一般,反转数字跟原始数字就相等或者相近了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package com.diguage.algorithm.leetcode;

import java.util.ArrayList;
import java.util.List;

/**
 * = 9. Palindrome Number
 *
 * https://leetcode.com/problems/palindrome-number/description/[Palindrome Number - LeetCode]
 *
 * Determine whether an integer is a palindrome. An integer is a palindrome when
 * it reads the same backward as forward.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: 121
 * Output: true
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: -121
 * Output: false
 * Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: 10
 * Output: false
 * Explanation: Reads 01 from right to left. Therefore it is not a palindrome.
 * ----
 *
 * == Follow up
 *
 * Coud you solve it without converting the integer to a string?
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-01
 */
public class _0009_PalindromeNumber {

  public static boolean isPalindrome(int x) {
    if (x < 0 || (x > 0 && x % 10 == 0)) {
      return false;
    }
    // 如果是回文数字,则反转之后数字相等。
    // 可以再进一步,不需要完全反转,只需要反转一半即可。
    int part = 0;
    while (x > part) {
      int digit = x % 10;
      part = part * 10 + digit;
      x /= 10;
    }
    // 这里分分两种情况:
    // abccba 型,则 x == part == abc
    // abcba  型,则 x == 12, part = abc,所以 x == part / 10
    return x == part || x == part / 10;
  }

  public static boolean isPalindromeDigits(int x) {
    boolean result = true;
    if (x < 0) {
      return false;
    }
    int multiBitNumStarter = 10;
    if (x < multiBitNumStarter) {
      return result;
    }
    List<Integer> bitNums = new ArrayList<>(25);
    for (int i = x; i > 0; i /= 10) {
      bitNums.add(i % 10);
    }
    int halfLength = bitNums.size() / 2;
    for (int i = 0; i < halfLength; i++) {
      if (!bitNums.get(i).equals(bitNums.get(bitNums.size() - i - 1))) {
        result = false;
        break;
      }
    }

    return result;
  }

  public static void main(String[] args) {
    System.out.println(isPalindrome(121));
    System.out.println(isPalindrome(-121));
    System.out.println(isPalindrome(10));
  }
}

10. Regular Expression Matching

Given an input string (s) and a pattern (p), 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).

Note:

  • s could be empty and contains only lowercase letters a-z.

  • p could be empty and contains only lowercase letters a-z, and characters like . or *.

Example 1:

Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".

Example 2:

Input:
s = "aa"
p = "a*"
Output: true
Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".

Example 3:

Input:
s = "ab"
p = "."
*Output: true
Explanation: "." means "zero or more () of any character (.)".

Example 4:

Input:
s = "aab"
p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches "aab".

Example 5:

Input:
s = "mississippi"
p = "mis*is*p*."
Output: false
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package com.diguage.algorithm.leetcode;

/**
 * = 10. Regular Expression Matching
 *
 * https://leetcode.com/problems/regular-expression-matching/[Regular Expression Matching - LeetCode]
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-04-26 18:56
 */
public class _0010_RegularExpressionMatching {
    // TODO Hard
}

11. Container With Most Water

Given n non-negative integers a1, a2, …​, a~n ~, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

*Note: *You may not slant the container and n is at least 2.

question 11

[.small]#The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49. #

Example:

Input: [1,8,6,2,5,4,8,3,7]
Output: 49

解题分析

双指针左右夹逼,保留高个,移动低个。

这里有个疑问,不考虑中间

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.diguage.algorithm.leetcode;

/**
 * = 11. Container With Most Water
 *
 * https://leetcode.com/problems/container-with-most-water/description/[Container With Most Water - LeetCode]
 *
 * Given n non-negative integers a1, a2, ..., an, where each represents a point
 * at coordinate (i, ai). n vertical lines are drawn such that the two endpoints
 * of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis
 * forms a container, such that the container contains the most water.
 *
 * Note: You may not slant the container and n is at least 2.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-13
 */
public class _0011_ContainerWithMostWater {
  public static int maxArea(int[] height) {
    int result = 0;
    int left = 0, right = height.length - 1;
    while (left < right) {
      int area = Math.min(height[left], height[right]) * (right - left);
      result = Math.max(result, area);
      if (height[left] < height[right]) {
        left++;
      } else {
        right--;
      }
    }
    return result;
  }

  public static void main(String[] args) {
    int[] height = new int[]{3, 8, 4, 7, 5, 9, 1, 2, 6};
    System.out.println(maxArea(height));
  }
}

12. Integer to Roman

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

For example, two is written as II in Roman numeral, just two one’s added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

  • I can be placed before V (5) and X (10) to make 4 and 9.

  • X can be placed before L (50) and C (100) to make 40 and 90.

  • C can be placed before D (500) and M (1000) to make 400 and 900.

Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.

Example 1:

Input: 3
Output: "III"

Example 2:

Input: 4
Output: "IV"

Example 3:

Input: 9
Output: "IX"

Example 4:

Input: 58
Output: "LVIII"
Explanation: L = 50, V = 5, III = 3.

Example 5:

Input: 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package com.diguage.algorithm.leetcode;

import java.util.*;

/**
 * = 12. Integer to Roman
 *
 * https://leetcode.com/problems/integer-to-roman/[Integer to Roman - LeetCode]
 *
 * Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
 *
 * [source]
 * ----
 * Symbol       Value
 * I             1
 * V             5
 * X             10
 * L             50
 * C             100
 * D             500
 * M             1000
 * ----
 *
 * For example, two is written as `II` in Roman numeral, just two one's added together.
 * Twelve is written as, `XII`, which is simply `X` + `II`. The number twenty seven is
 * written as XXVII, which is `XX` + `V` + `II`.
 *
 * Roman numerals are usually written largest to smallest from left to right. However,
 * the numeral for four is not `IIII`. Instead, the number four is written as `IV`.
 * Because the one is before the five we subtract it making four. The same principle
 * applies to the number nine, which is written as `IX`. There are six instances
 * where subtraction is used:
 *
 * * `I` can be placed before `V` (5) and `X` (10) to make 4 and 9.
 * * `X` can be placed before `L` (50) and `C` (100) to make 40 and 90.
 * * `C` can be placed before `D` (500) and `M` (1000) to make 400 and 900.
 *
 * Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: 3
 * Output: "III"
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: 4
 * Output: "IV"
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: 9
 * Output: "IX"
 * ----
 *
 * .Example 4:
 * [source]
 * ----
 * Input: 58
 * Output: "LVIII"
 * Explanation: L = 50, V= 5, III = 3.
 * ----
 *
 * .Example 5:
 * [source]
 * ----
 * Input: 1994
 * Output: "MCMXCIV"
 * Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-17 10:45
 */
public class _0012_IntegerToRoman {
    /**
     * Runtime: 46 ms, faster than 5.34% of Java online submissions for Integer to Roman.
     *
     * Memory Usage: 44.1 MB, less than 5.01% of Java online submissions for Integer to Roman.
     *
     * @since 2019-07-17 11:24:02
     */
    public String intToRoman(int num) {
        Map<Integer, String> i2r = new HashMap<>(19);
        i2r.put(1, "I");
        i2r.put(5, "V");
        i2r.put(10, "X");
        i2r.put(50, "L");
        i2r.put(100, "C");
        i2r.put(500, "D");
        i2r.put(1000, "M");
        i2r.put(4, "IV");
        i2r.put(9, "IX");
        i2r.put(40, "XL");
        i2r.put(90, "XC");
        i2r.put(400, "CD");
        i2r.put(900, "CM");

        StringBuilder builder = new StringBuilder(20);

        int size = i2r.size();
        int temp = num;

        Integer[] keys = i2r.keySet().toArray(new Integer[0]);
        Arrays.sort(keys, Comparator.comparingInt(a -> -a));

        int lastIndex = 0;
        while (temp > 0) {
            for (int i = lastIndex; i < size; i++) {
                Integer key = keys[i];
                if (temp >= key) {
                    lastIndex = i;
                    temp -= key;
                    builder.append(i2r.get(key));
                    break;
                }
            }
        }

        return builder.toString();
    }

    public static void main(String[] args) {
        _0012_IntegerToRoman solution = new _0012_IntegerToRoman();

        String roman5 = solution.intToRoman(1994);
        System.out.println("MCMXCIV".equals(roman5) + " : " + roman5);


        String roman = solution.intToRoman(3);
        System.out.println("III".equals(roman) + " : " + roman);

        String roman2 = solution.intToRoman(4);
        System.out.println("IV".equals(roman2) + " : " + roman2);

        String roman3 = solution.intToRoman(9);
        System.out.println("IX".equals(roman3) + " : " + roman3);

        String roman4 = solution.intToRoman(58);
        System.out.println("LVIII".equals(roman4) + " : " + roman4);
    }
}

13. Roman to Integer

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

For example, two is written as II in Roman numeral, just two one’s added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

  • I can be placed before V (5) and X (10) to make 4 and 9.

  • X can be placed before L (50) and C (100) to make 40 and 90.

  • C can be placed before D (500) and M (1000) to make 400 and 900.

Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.

Example 1:

Input: "III"
Output: 3

Example 2:

Input: "IV"
Output: 4

Example 3:

Input: "IX"
Output: 9

Example 4:

Input: "LVIII"
Output: 58
Explanation: L = 50, V= 5, III = 3.

Example 5:

Input: "MCMXCIV"
Output: 1994
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

解题分析

查看罗马数字,如果左边的数字比右边大,则就是需要做减法,否则做加法。

0013 0
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package com.diguage.algorithm.leetcode;

import java.util.HashMap;
import java.util.Objects;

/**
 * = 13. Roman to Integer
 *
 * https://leetcode.com/problems/roman-to-integer/[Roman to Integer - LeetCode]
 *
 * Roman numerals are represented by seven different symbols: `I`, `V`, `X`, `L`, `C`, `D` and `M`.
 *
 * [source]
 * ----
 * Symbol       Value
 * I             1
 * V             5
 * X             10
 * L             50
 * C             100
 * D             500
 * M             1000
 * ----
 *
 * For example, two is written as `II` in Roman numeral, just two one's added together.
 * Twelve is written as, `XII`, which is simply `X` + `II`. The number twenty seven is
 * written as XXVII, which is `XX` + `V` + `II`.
 *
 * Roman numerals are usually written largest to smallest from left to right. However,
 * the numeral for four is not `IIII`. Instead, the number four is written as `IV`.
 * Because the one is before the five we subtract it making four. The same principle
 * applies to the number nine, which is written as `IX`. There are six instances
 * where subtraction is used:
 *
 * * `I` can be placed before `V` (5) and `X` (10) to make 4 and 9.
 * * `X` can be placed before `L` (50) and `C` (100) to make 40 and 90.
 * * `C` can be placed before `D` (500) and `M` (1000) to make 400 and 900.
 *
 * Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: "III"
 * Output: 3
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: "IV"
 * Output: 4
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: "IX"
 * Output: 9
 * ----
 *
 * .Example 4:
 * [source]
 * ----
 * Input: "LVIII"
 * Output: 58
 * Explanation: L = 50, V= 5, III = 3.
 * ----
 *
 * .Example 5:
 * [source]
 * ----
 * Input: "MCMXCIV"
 * Output: 1994
 * Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-11 17:14
 */
public class _0013_RomanToInteger {

  // 从右向左,从小到大,更容易理解
  public int romanToInt(String s) {
    int result = 0;
    int pre = 0;
    for (int i = s.length() - 1; i >= 0; i--) {
      int curr = charToNum(s.charAt(i));
      if (curr >= pre) {
        result += curr;
      } else {
        result -= curr;
      }
      pre = curr;
    }
    return result;
  }

  private int charToNum(char c) {
    switch (c) {
      case 'I': return 1;
      case 'V': return 5;
      case 'X': return 10;
      case 'L': return 50;
      case 'C': return 100;
      case 'D': return 500;
      case 'M': return 1000;
      default: return 0;
    }
  }

  // 从左向右处理
  public int romanToIntLeftToRight(String s) {
    int result = 0;
    int prenum = charToNum(s.charAt(0));
    for (int i = 1; i < s.length(); i++) {
      int num = charToNum(s.charAt(i));
      if (prenum < num) {
        result -= prenum;
      } else {
        result += prenum;
      }
      prenum = num;
    }
    result += prenum;
    return result;
  }

  public int romanToInt2(String s) {
    int result = 0;
    if (Objects.isNull(s) || s.length() == 0) {
      return result;
    }

    HashMap<String, Integer> r2i = new HashMap<>();
    r2i.put("I", 1);
    r2i.put("V", 5);
    r2i.put("X", 10);
    r2i.put("L", 50);
    r2i.put("C", 100);
    r2i.put("D", 500);
    r2i.put("M", 1000);
    r2i.put("IV", 4);
    r2i.put("IX", 9);
    r2i.put("XL", 40);
    r2i.put("XC", 90);
    r2i.put("CD", 400);
    r2i.put("CM", 900);

    for (int i = s.length(); i > 0; ) {
      int step = 2;
      int beginIndex = i - step;
      if (beginIndex < 0) {
        beginIndex = 0;
      }
      String symbol = s.substring(beginIndex, i);
      Integer value = r2i.get(symbol);
      if (Objects.isNull(value)) {
        step = 1;
        beginIndex = i - step;
        if (beginIndex < 0) {
          beginIndex = 0;
        }
        symbol = s.substring(beginIndex, i);
        value = r2i.get(symbol);
      }
      result += value;
      i -= step;
    }
    return result;
  }

  public static void main(String[] args) {
    _0013_RomanToInteger roman = new _0013_RomanToInteger();
    System.out.println(roman.romanToInt("III") == 3);
    System.out.println(roman.romanToInt("IV") == 4);
    System.out.println(roman.romanToInt("IX") == 9);
    System.out.println(roman.romanToInt("LVIII") == 58);
    System.out.println(roman.romanToInt("MCMXCIV") == 1994);
  }
}

14. Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings.

If there is no common prefix, return an empty string "".

Example 1:

Input: ["flower","flow","flight"]
Output: "fl"

Example 2:

Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.

Note:

All given inputs are in lowercase letters a-z.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 14. Longest Common Prefix
 *
 * https://leetcode.com/problems/longest-common-prefix/[Longest Common Prefix - LeetCode]
 *
 * Write a function to find the longest common prefix string amongst an array of strings.
 *
 * If there is no common prefix, return an empty string "".
 *
 * .Example 1:
 * [source]
 * ----
 * Input: ["flower","flow","flight"]
 * Output: "fl"
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: ["dog","racecar","car"]
 * Output: ""
 * Explanation: There is no common prefix among the input strings.
 * ----
 *
 * *Note:*
 *
 * All given inputs are in lowercase letters `a-z`.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-11 17:50
 */
public class _0014_LongestCommonPrefix {

  /**
   * 使用逐列扫描前进,遇到不同时,则终止。
   */
  public String longestCommonPrefix(String[] strs) {
    if (Objects.isNull(strs) || strs.length == 0) {
      return "";
    }
    for (int i = 0; i < strs[0].length(); i++) {
      char c = strs[0].charAt(i);
      for (int j = 1; j < strs.length; j++) {
        if (i == strs[j].length() || strs[j].charAt(i) != c) {
          return strs[0].substring(0, i);
        }
      }
    }
    return strs[0];
  }

  public String longestCommonPrefix2(String[] strs) {
    if (Objects.isNull(strs) || strs.length == 0) {
      return "";
    }
    if (strs.length == 1) {
      return strs[0];
    }
    int maxLength = Integer.MAX_VALUE;
    for (String str : strs) {
      int strLength = str.length();
      if (strLength < maxLength) {
        maxLength = strLength;
      }
    }

    int length = 0;

    loop:
    while (length < maxLength) {
      char aChar = strs[0].charAt(length);
      for (int i = 1; i < strs.length; i++) {
        char bChar = strs[i].charAt(length);
        if (aChar != bChar) {
          break loop;
        }
      }
      length += 1;
    }
    if (length > 0) {
      return strs[0].substring(0, length);
    } else {
      return "";
    }
  }

  public static void main(String[] args) {
    _0014_LongestCommonPrefix prefix = new _0014_LongestCommonPrefix();
    String prefix1 = prefix.longestCommonPrefix(new String[]{"flower", "flow", "flight"});
    System.out.println("fl".equals(prefix1) + " " + prefix1);
    System.out.println("".equals(prefix.longestCommonPrefix(new String[]{"dog", "racecar", "car"})));
  }
}

15. 3Sum

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解题分析

为什么参考资料中,JS 的代码可以通过,但是转成 Java 之后就不能通过呢?

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
package com.diguage.algorithm.leetcode;

import java.util.*;
import java.util.stream.Collectors;

/**
 * = 15. 3Sum
 *
 * https://leetcode.com/problems/3sum/description/[3Sum - LeetCode]
 *
 * Given an array `nums` of n integers, are there elements `a`, `b`, `c` in
 * `nums` such that `a + b + c = 0`? Find all unique triplets in the array
 * which gives the sum of zero.
 *
 * == Note
 *
 * The solution set must not contain duplicate triplets.
 *
 * .Example:
 * [source]
 * ----
 * Given array nums = [-1, 0, 1, 2, -1, -4],
 *
 * A solution set is:
 * [
 *   [-1, 0, 1],
 *   [-1, -1, 2]
 * ]
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-19
 */
public class _0015_3Sum {
  // TODO 还没有通过
  public static List<List<Integer>> threeSum(int[] nums) {
    if (Objects.isNull(nums) || nums.length < 3) {
      return Collections.emptyList();
    }
    List<List<Integer>> result = new ArrayList<>();
    Arrays.sort(nums);
    if (nums[0] * nums[nums.length - 1] > 0) {
      return result;
    }
    for (int i = 0; i < nums.length - 2 && nums[i] <= 0; ) {
      int left = i + 1, right = nums.length - 1;
      while (left < right && nums[i] * nums[right] <= 0) {
        int sum = nums[i] + nums[left] + nums[right];
        if (sum == 0) {
          result.add(Arrays.asList(nums[i], nums[left], nums[right]));
        }
        if (sum > 0) {
          while (left < right && nums[right] == nums[--right]) {}
        } else {
          while (left < right && nums[left] == nums[++left]) {}
        }
      }
      while (i < nums.length - 1 && nums[i] == nums[++i]) {}
    }
    return result;
  }

  public static List<List<Integer>> threeSum2(int[] nums) {
    if (nums.length < 3) {
      return new ArrayList<>();
    }
    Set<List<Integer>> result = new HashSet<>();

    Arrays.sort(nums);

    Map<Integer, Integer> numMap = new HashMap<>(nums.length * 4 / 3 + 1);
    for (int i = 0; i < nums.length; i++) {
      numMap.put(nums[i], i);
    }

    if (numMap.size() == 1 && numMap.keySet().contains(0)) {
      result.add(Arrays.asList(0, 0, 0));
      return new ArrayList<>(result);
    }

    for (int i = 0; i < nums.length; i++) {
      for (int j = nums.length - 1; j > i; j--) {
        int minuend = 0 - (nums[i] + nums[j]);
        if (numMap.containsKey(minuend)) {
          Integer k = numMap.get(minuend);
          if (i != k && j != k) {
            int[] oneResult = new int[]{nums[i], nums[j], minuend};
            Arrays.sort(oneResult);
            result.add(Arrays.stream(oneResult).boxed().collect(Collectors.toList()));
          }
        }
      }
    }

    return new ArrayList<>(result);
  }

  public static void main(String[] args) {
//        int[] nums = {-1, 0, 1, 2, -1, -4};
    int[] nums = {82597, -9243, 62390, 83030, -97960, -26521, -61011, 83390, -38677, 12333, 75987, 46091, 83794, 19355, -71037, -6242, -28801, 324, 1202, -90885, -2989, -95597, -34333, 35528, 5680, 89093, -90606, 50360, -29393, -27012, 53313, 65213, 99818, -82405, -41661, -3333, -51952, 72135, -1523, 26377, 74685, 96992, 92263, 15929, 5467, -99555, -43348, -41689, -60383, -3990, 32165, 65265, -72973, -58372, 12741, -48568, -46596, 72419, -1859, 34153, 62937, 81310, -61823, -96770, -54944, 8845, -91184, 24208, -29078, 31495, 65258, 14198, 85395, 70506, -40908, 56740, -12228, -40072, 32429, 93001, 68445, -73927, 25731, -91859, -24150, 10093, -60271, -81683, -18126, 51055, 48189, -6468, 25057, 81194, -58628, 74042, 66158, -14452, -49851, -43667, 11092, 39189, -17025, -79173, 13606, 83172, 92647, -59741, 19343, -26644, -57607, 82908, -20655, 1637, 80060, 98994, 39331, -31274, -61523, 91225, -72953, 13211, -75116, -98421, -41571, -69074, 99587, 39345, 42151, -2460, 98236, 15690, -52507, -95803, -48935, -46492, -45606, -79254, -99851, 52533, 73486, 39948, -7240, 71815, -585, -96252, 90990, -93815, 93340, -71848, 58733, -14859, -83082, -75794, -82082, -24871, -15206, 91207, -56469, -93618, 67131, -8682, 75719, 87429, -98757, -7535, -24890, -94160, 85003, 33928, 75538, 97456, -66424, -60074, -8527, -28697, -22308, 2246, -70134, -82319, -10184, 87081, -34949, -28645, -47352, -83966, -60418, -15293, -53067, -25921, 55172, 75064, 95859, 48049, 34311, -86931, -38586, 33686, -36714, 96922, 76713, -22165, -80585, -34503, -44516, 39217, -28457, 47227, -94036, 43457, 24626, -87359, 26898, -70819, 30528, -32397, -69486, 84912, -1187, -98986, -32958, 4280, -79129, -65604, 9344, 58964, 50584, 71128, -55480, 24986, 15086, -62360, -42977, -49482, -77256, -36895, -74818, 20, 3063, -49426, 28152, -97329, 6086, 86035, -88743, 35241, 44249, 19927, -10660, 89404, 24179, -26621, -6511, 57745, -28750, 96340, -97160, -97822, -49979, 52307, 79462, 94273, -24808, 77104, 9255, -83057, 77655, 21361, 55956, -9096, 48599, -40490, -55107, 2689, 29608, 20497, 66834, -34678, 23553, -81400, -66630, -96321, -34499, -12957, -20564, 25610, -4322, -58462, 20801, 53700, 71527, 24669, -54534, 57879, -3221, 33636, 3900, 97832, -27688, -98715, 5992, 24520, -55401, -57613, -69926, 57377, -77610, 20123, 52174, 860, 60429, -91994, -62403, -6218, -90610, -37263, -15052, 62069, -96465, 44254, 89892, -3406, 19121, -41842, -87783, -64125, -56120, 73904, -22797, -58118, -4866, 5356, 75318, 46119, 21276, -19246, -9241, -97425, 57333, -15802, 93149, 25689, -5532, 95716, 39209, -87672, -29470, -16324, -15331, 27632, -39454, 56530, -16000, 29853, 46475, 78242, -46602, 83192, -73440, -15816, 50964, -36601, 89758, 38375, -40007, -36675, -94030, 67576, 46811, -64919, 45595, 76530, 40398, 35845, 41791, 67697, -30439, -82944, 63115, 33447, -36046, -50122, -34789, 43003, -78947, -38763, -89210, 32756, -20389, -31358, -90526, -81607, 88741, 86643, 98422, 47389, -75189, 13091, 95993, -15501, 94260, -25584, -1483, -67261, -70753, 25160, 89614, -90620, -48542, 83889, -12388, -9642, -37043, -67663, 28794, -8801, 13621, 12241, 55379, 84290, 21692, -95906, -85617, -17341, -63767, 80183, -4942, -51478, 30997, -13658, 8838, 17452, -82869, -39897, 68449, 31964, 98158, -49489, 62283, -62209, -92792, -59342, 55146, -38533, 20496, 62667, 62593, 36095, -12470, 5453, -50451, 74716, -17902, 3302, -16760, -71642, -34819, 96459, -72860, 21638, 47342, -69897, -40180, 44466, 76496, 84659, 13848, -91600, -90887, -63742, -2156, -84981, -99280, 94326, -33854, 92029, -50811, 98711, -36459, -75555, 79110, -88164, -97397, -84217, 97457, 64387, 30513, -53190, -83215, 252, 2344, -27177, -92945, -89010, 82662, -11670, 86069, 53417, 42702, 97082, 3695, -14530, -46334, 17910, 77999, 28009, -12374, 15498, -46941, 97088, -35030, 95040, 92095, -59469, -24761, 46491, 67357, -66658, 37446, -65130, -50416, 99197, 30925, 27308, 54122, -44719, 12582, -99525, -38446, -69050, -22352, 94757, -56062, 33684, -40199, -46399, 96842, -50881, -22380, -65021, 40582, 53623, -76034, 77018, -97074, -84838, -22953, -74205, 79715, -33920, -35794, -91369, 73421, -82492, 63680, -14915, -33295, 37145, 76852, -69442, 60125, -74166, 74308, -1900, -30195, -16267, -60781, -27760, 5852, 38917, 25742, -3765, 49097, -63541, 98612, -92865, -30248, 9612, -8798, 53262, 95781, -42278, -36529, 7252, -27394, -5021, 59178, 80934, -48480, -75131, -54439, -19145, -48140, 98457, -6601, -51616, -89730, 78028, 32083, -48904, 16822, -81153, -8832, 48720, -80728, -45133, -86647, -4259, -40453, 2590, 28613, 50523, -4105, -27790, -74579, -17223, 63721, 33489, -47921, 97628, -97691, -14782, -65644, 18008, -93651, -71266, 80990, -76732, -47104, 35368, 28632, 59818, -86269, -89753, 34557, -92230, -5933, -3487, -73557, -13174, -43981, -43630, -55171, 30254, -83710, -99583, -13500, 71787, 5017, -25117, -78586, 86941, -3251, -23867, -36315, 75973, 86272, -45575, 77462, -98836, -10859, 70168, -32971, -38739, -12761, 93410, 14014, -30706, -77356, -85965, -62316, 63918, -59914, -64088, 1591, -10957, 38004, 15129, -83602, -51791, 34381, -89382, -26056, 8942, 5465, 71458, -73805, -87445, -19921, -80784, 69150, -34168, 28301, -68955, 18041, 6059, 82342, 9947, 39795, 44047, -57313, 48569, 81936, -2863, -80932, 32976, -86454, -84207, 33033, 32867, 9104, -16580, -25727, 80157, -70169, 53741, 86522, 84651, 68480, 84018, 61932, 7332, -61322, -69663, 76370, 41206, 12326, -34689, 17016, 82975, -23386, 39417, 72793, 44774, -96259, 3213, 79952, 29265, -61492, -49337, 14162, 65886, 3342, -41622, -62659, -90402, -24751, 88511, 54739, -21383, -40161, -96610, -24944, -602, -76842, -21856, 69964, 43994, -15121, -85530, 12718, 13170, -13547, 69222, 62417, -75305, -81446, -38786, -52075, -23110, 97681, -82800, -53178, 11474, 35857, 94197, -58148, -23689, 32506, 92154, -64536, -73930, -77138, 97446, -83459, 70963, 22452, 68472, -3728, -25059, -49405, 95129, -6167, 12808, 99918, 30113, -12641, -26665, 86362, -33505, 50661, 26714, 33701, 89012, -91540, 40517, -12716, -57185, -87230, 29914, -59560, 13200, -72723, 58272, 23913, -45586, -96593, -26265, -2141, 31087, 81399, 92511, -34049, 20577, 2803, 26003, 8940, 42117, 40887, -82715, 38269, 40969, -50022, 72088, 21291, -67280, -16523, 90535, 18669, 94342, -39568, -88080, -99486, -20716, 23108, -28037, 63342, 36863, -29420, -44016, 75135, 73415, 16059, -4899, 86893, 43136, -7041, 33483, -67612, 25327, 40830, 6184, 61805, 4247, 81119, -22854, -26104, -63466, 63093, -63685, 60369, 51023, 51644, -16350, 74438, -83514, 99083, 10079, -58451, -79621, 48471, 67131, -86940, 99093, 11855, -22272, -67683, -44371, 9541, 18123, 37766, -70922, 80385, -57513, -76021, -47890, 36154, 72935, 84387, -92681, -88303, -7810, 59902, -90, -64704, -28396, -66403, 8860, 13343, 33882, 85680, 7228, 28160, -14003, 54369, -58893, 92606, -63492, -10101, 64714, 58486, 29948, -44679, -22763, 10151, -56695, 4031, -18242, -36232, 86168, -14263, 9883, 47124, 47271, 92761, -24958, -73263, -79661, -69147, -18874, 29546, -92588, -85771, 26451, -86650, -43306, -59094, -47492, -34821, -91763, -47670, 33537, 22843, 67417, -759, 92159, 63075, 94065, -26988, 55276, 65903, 30414, -67129, -99508, -83092, -91493, -50426, 14349, -83216, -76090, 32742, -5306, -93310, -60750, -60620, -45484, -21108, -58341, -28048, -52803, 69735, 78906, 81649, 32565, -86804, -83202, -65688, -1760, 89707, 93322, -72750, 84134, 71900, -37720, 19450, -78018, 22001, -23604, 26276, -21498, 65892, -72117, -89834, -23867, 55817, -77963, 42518, 93123, -83916, 63260, -2243, -97108, 85442, -36775, 17984, -58810, 99664, -19082, 93075, -69329, 87061, 79713, 16296, 70996, 13483, -74582, 49900, -27669, -40562, 1209, -20572, 34660, 83193, 75579, 7344, 64925, 88361, 60969, 3114, 44611, -27445, 53049, -16085, -92851, -53306, 13859, -33532, 86622, -75666, -18159, -98256, 51875, -42251, -27977, -18080, 23772, 38160, 41779, 9147, 94175, 99905, -85755, 62535, -88412, -52038, -68171, 93255, -44684, -11242, -104, 31796, 62346, -54931, -55790, -70032, 46221, 56541, -91947, 90592, 93503, 4071, 20646, 4856, -63598, 15396, -50708, 32138, -85164, 38528, -89959, 53852, 57915, -42421, -88916, -75072, 67030, -29066, 49542, -71591, 61708, -53985, -43051, 28483, 46991, -83216, 80991, -46254, -48716, 39356, -8270, -47763, -34410, 874, -1186, -7049, 28846, 11276, 21960, -13304, -11433, -4913, 55754, 79616, 70423, -27523, 64803, 49277, 14906, -97401, -92390, 91075, 70736, 21971, -3303, 55333, -93996, 76538, 54603, -75899, 98801, 46887, 35041, 48302, -52318, 55439, 24574, 14079, -24889, 83440, 14961, 34312, -89260, -22293, -81271, -2586, -71059, -10640, -93095, -5453, -70041, 66543, 74012, -11662, -52477, -37597, -70919, 92971, -17452, -67306, -80418, 7225, -89296, 24296, 86547, 37154, -10696, 74436, -63959, 58860, 33590, -88925, -97814, -83664, 85484, -8385, -50879, 57729, -74728, -87852, -15524, -91120, 22062, 28134, 80917, 32026, 49707, -54252, -44319, -35139, 13777, 44660, 85274, 25043, 58781, -89035, -76274, 6364, -63625, 72855, 43242, -35033, 12820, -27460, 77372, -47578, -61162, -70758, -1343, -4159, 64935, 56024, -2151, 43770, 19758, -30186, -86040, 24666, -62332, -67542, 73180, -25821, -27826, -45504, -36858, -12041, 20017, -24066, -56625, -52097, -47239, -90694, 8959, 7712, -14258, -5860, 55349, 61808, -4423, -93703, 64681, -98641, -25222, 46999, -83831, -54714, 19997, -68477, 66073, 51801, -66491, 52061, -52866, 79907, -39736, -68331, 68937, 91464, 98892, 910, 93501, 31295, -85873, 27036, -57340, 50412, 21, -2445, 29471, 71317, 82093, -94823, -54458, -97410, 39560, -7628, 66452, 39701, 54029, 37906, 46773, 58296, 60370, -61090, 85501, -86874, 71443, -72702, -72047, 14848, 34102, 77975, -66294, -36576, 31349, 52493, -70833, -80287, 94435, 39745, -98291, 84524, -18942, 10236, 93448, 50846, 94023, -6939, 47999, 14740, 30165, 81048, 84935, -19177, -13594, 32289, 62628, -90612, -542, -66627, 64255, 71199, -83841, -82943, -73885, 8623, -67214, -9474, -35249, 62254, -14087, -90969, 21515, -83303, 94377, -91619, 19956, -98810, 96727, -91939, 29119, -85473, -82153, -69008, 44850, 74299, -76459, -86464, 8315, -49912, -28665, 59052, -69708, 76024, -92738, 50098, 18683, -91438, 18096, -19335, 35659, 91826, 15779, -73070, 67873, -12458, -71440, -46721, 54856, 97212, -81875, 35805, 36952, 68498, 81627, -34231, 81712, 27100, -9741, -82612, 18766, -36392, 2759, 41728, 69743, 26825, 48355, -17790, 17165, 56558, 3295, -24375, 55669, -16109, 24079, 73414, 48990, -11931, -78214, 90745, 19878, 35673, -15317, -89086, 94675, -92513, 88410, -93248, -19475, -74041, -19165, 32329, -26266, -46828, -18747, 45328, 8990, -78219, -25874, -74801, -44956, -54577, -29756, -99822, -35731, -18348, -68915, -83518, -53451, 95471, -2954, -13706, -8763, -21642, -37210, 16814, -60070, -42743, 27697, -36333, -42362, 11576, 85742, -82536, 68767, -56103, -63012, 71396, -78464, -68101, -15917, -11113, -3596, 77626, -60191, -30585, -73584, 6214, -84303, 18403, 23618, -15619, -89755, -59515, -59103, -74308, -63725, -29364, -52376, -96130, 70894, -12609, 50845, -2314, 42264, -70825, 64481, 55752, 4460, -68603, -88701, 4713, -50441, -51333, -77907, 97412, -66616, -49430, 60489, -85262, -97621, -18980, 44727, -69321, -57730, 66287, -92566, -64427, -14270, 11515, -92612, -87645, 61557, 24197, -81923, -39831, -10301, -23640, -76219, -68025, 92761, -76493, 68554, -77734, -95620, -11753, -51700, 98234, -68544, -61838, 29467, 46603, -18221, -35441, 74537, 40327, -58293, 75755, -57301, -7532, -94163, 18179, -14388, -22258, -46417, -48285, 18242, -77551, 82620, 250, -20060, -79568, -77259, 82052, -98897, -75464, 48773, -79040, -11293, 45941, -67876, -69204, -46477, -46107, 792, 60546, -34573, -12879, -94562, 20356, -48004, -62429, 96242, 40594, 2099, 99494, 25724, -39394, -2388, -18563, -56510, -83570, -29214, 3015, 74454, 74197, 76678, -46597, 60630, -76093, 37578, -82045, -24077, 62082, -87787, -74936, 58687, 12200, -98952, 70155, -77370, 21710, -84625, -60556, -84128, 925, 65474, -15741, -94619, 88377, 89334, 44749, 22002, -45750, -93081, -14600, -83447, 46691, 85040, -66447, -80085, 56308, 44310, 24979, -29694, 57991, 4675, -71273, -44508, 13615, -54710, 23552, -78253, -34637, 50497, 68706, 81543, -88408, -21405, 6001, -33834, -21570, -46692, -25344, 20310, 71258, -97680, 11721, 59977, 59247, -48949, 98955, -50276, -80844, -27935, -76102, 55858, -33492, 40680, 66691, -33188, 8284, 64893, -7528, 6019, -85523, 8434, -64366, -56663, 26862, 30008, -7611, -12179, -70076, 21426, -11261, -36864, -61937, -59677, 929, -21052, 3848, -20888, -16065, 98995, -32293, -86121, -54564, 77831, 68602, 74977, 31658, 40699, 29755, 98424, 80358, -69337, 26339, 13213, -46016, -18331, 64713, -46883, -58451, -70024, -92393, -4088, 70628, -51185, 71164, -75791, -1636, -29102, -16929, -87650, -84589, -24229, -42137, -15653, 94825, 13042, 88499, -47100, -90358, -7180, 29754, -65727, -42659, -85560, -9037, -52459, 20997, -47425, 17318, 21122, 20472, -23037, 65216, -63625, -7877, -91907, 24100, -72516, 22903, -85247, -8938, 73878, 54953, 87480, -31466, -99524, 35369, -78376, 89984, -15982, 94045, -7269, 23319, -80456, -37653, -76756, 2909, 81936, 54958, -12393, 60560, -84664, -82413, 66941, -26573, -97532, 64460, 18593, -85789, -38820, -92575, -43663, -89435, 83272, -50585, 13616, -71541, -53156, 727, -27644, 16538, 34049, 57745, 34348, 35009, 16634, -18791, 23271, -63844, 95817, 21781, 16590, 59669, 15966, -6864, 48050, -36143, 97427, -59390, 96931, 78939, -1958, 50777, 43338, -51149, 39235, -27054, -43492, 67457, -83616, 37179, 10390, 85818, 2391, 73635, 87579, -49127, -81264, -79023, -81590, 53554, -74972, -83940, -13726, -39095, 29174, 78072, 76104, 47778, 25797, -29515, -6493, -92793, 22481, -36197, -65560, 42342, 15750, 97556, 99634, -56048, -35688, 13501, 63969, -74291, 50911, 39225, 93702, -3490, -59461, -30105, -46761, -80113, 92906, -68487, 50742, 36152, -90240, -83631, 24597, -50566, -15477, 18470, 77038, 40223, -80364, -98676, 70957, -63647, 99537, 13041, 31679, 86631, 37633, -16866, 13686, -71565, 21652, -46053, -80578, -61382, 68487, -6417, 4656, 20811, 67013, -30868, -11219, 46, 74944, 14627, 56965, 42275, -52480, 52162, -84883, -52579, -90331, 92792, 42184, -73422, -58440, 65308, -25069, 5475, -57996, 59557, -17561, 2826, -56939, 14996, -94855, -53707, 99159, 43645, -67719, -1331, 21412, 41704, 31612, 32622, 1919, -69333, -69828, 22422, -78842, 57896, -17363, 27979, -76897, 35008, 46482, -75289, 65799, 20057, 7170, 41326, -76069, 90840, -81253, -50749, 3649, -42315, 45238, -33924, 62101, 96906, 58884, -7617, -28689, -66578, 62458, 50876, -57553, 6739, 41014, -64040, -34916, 37940, 13048, -97478, -11318, -89440, -31933, -40357, -59737, -76718, -14104, -31774, 28001, 4103, 41702, -25120, -31654, 63085, -3642, 84870, -83896, -76422, -61520, 12900, 88678, 85547, 33132, -88627, 52820, 63915, -27472, 78867, -51439, 33005, -23447, -3271, -39308, 39726, -74260, -31874, -36893, 93656, 910, -98362, 60450, -88048, 99308, 13947, 83996, -90415, -35117, 70858, -55332, -31721, 97528, 82982, -86218, 6822, 25227, 36946, 97077, -4257, -41526, 56795, 89870, 75860, -70802, 21779, 14184, -16511, -89156, -31422, 71470, 69600, -78498, 74079, -19410, 40311, 28501, 26397, -67574, -32518, 68510, 38615, 19355, -6088, -97159, -29255, -92523, 3023, -42536, -88681, 64255, 41206, 44119, 52208, 39522, -52108, 91276, -70514, 83436, 63289, -79741, 9623, 99559, 12642, 85950, 83735, -21156, -67208, 98088, -7341, -27763, -30048, -44099, -14866, -45504, -91704, 19369, 13700, 10481, -49344, -85686, 33994, 19672, 36028, 60842, 66564, -24919, 33950, -93616, -47430, -35391, -28279, 56806, 74690, 39284, -96683, -7642, -75232, 37657, -14531, -86870, -9274, -26173, 98640, 88652, 64257, 46457, 37814, -19370, 9337, -22556, -41525, 39105, -28719, 51611, -93252, 98044, -90996, 21710, -47605, -64259, -32727, 53611, -31918, -3555, 33316, -66472, 21274, -37731, -2919, 15016, 48779, -88868, 1897, 41728, 46344, -89667, 37848, 68092, -44011, 85354, -43776, 38739, -31423, -66330, 65167, -22016, 59405, 34328, -60042, 87660, -67698, -59174, -1408, -46809, -43485, -88807, -60489, 13974, 22319, 55836, -62995, -37375, -4185, 32687, -36551, -75237, 58280, 26942, -73756, 71756, 78775, -40573, 14367, -71622, -77338, 24112, 23414, -7679, -51721, 87492, 85066, -21612, 57045, 10673, -96836, 52461, -62218, -9310, 65862, -22748, 89906, -96987, -98698, 26956, -43428, 46141, 47456, 28095, 55952, 67323, -36455, -60202, -43302, -82932, 42020, 77036, 10142, 60406, 70331, 63836, 58850, -66752, 52109, 21395, -10238, -98647, -41962, 27778, 69060, 98535, -28680, -52263, -56679, 66103, -42426, 27203, 80021, 10153, 58678, 36398, 63112, 34911, 20515, 62082, -15659, -40785, 27054, 43767, -20289, 65838, -6954, -60228, -72226, 52236, -35464, 25209, -15462, -79617, -41668, -84083, 62404, -69062, 18913, 46545, 20757, 13805, 24717, -18461, -47009, -25779, 68834, 64824, 34473, 39576, 31570, 14861, -15114, -41233, 95509, 68232, 67846, 84902, -83060, 17642, -18422, 73688, 77671, -26930, 64484, -99637, 73875, 6428, 21034, -73471, 19664, -68031, 15922, -27028, 48137, 54955, -82793, -41144, -10218, -24921, -28299, -2288, 68518, -54452, 15686, -41814, 66165, -72207, -61986, 80020, 50544, -99500, 16244, 78998, 40989, 14525, -56061, -24692, -94790, 21111, 37296, -90794, 72100, 70550, -31757, 17708, -74290, 61910, 78039, -78629, -25033, 73172, -91953, 10052, 64502, 99585, -1741, 90324, -73723, 68942, 28149, 30218, 24422, 16659, 10710, -62594, 94249, 96588, 46192, 34251, 73500, -65995, -81168, 41412, -98724, -63710, -54696, -52407, 19746, 45869, 27821, -94866, -76705, -13417, -61995, -71560, 43450, 67384, -8838, -80293, -28937, 23330, -89694, -40586, 46918, 80429, -5475, 78013, 25309, -34162, 37236, -77577, 86744, 26281, -29033, -91813, 35347, 13033, -13631, -24459, 3325, -71078, -75359, 81311, 19700, 47678, -74680, -84113, 45192, 35502, 37675, 19553, 76522, -51098, -18211, 89717, 4508, -82946, 27749, 85995, 89912, -53678, -64727, -14778, 32075, -63412, -40524, 86440, -2707, -36821, 63850, -30883, 67294, -99468, -23708, 34932, 34386, 98899, 29239, -23385, 5897, 54882, 98660, 49098, 70275, 17718, 88533, 52161, 63340, 50061, -89457, 19491, -99156, 24873, -17008, 64610, -55543, 50495, 17056, -10400, -56678, -29073, -42960, -76418, 98562, -88104, -96255, 10159, -90724, 54011, 12052, 45871, -90933, -69420, 67039, 37202, 78051, -52197, -40278, -58425, 65414, -23394, -1415, 6912, -53447, 7352, 17307, -78147, 63727, 98905, 55412, -57658, -32884, -44878, 22755, 39730, 3638, 35111, 39777, 74193, 38736, -11829, -61188, -92757, 55946, -71232, -63032, -83947, 39147, -96684, -99233, 25131, -32197, 24406, -55428, -61941, 25874, -69453, 64483, -19644, -68441, 12783, 87338, -48676, 66451, -447, -61590, 50932, -11270, 29035, 65698, -63544, 10029, 80499, -9461, 86368, 91365, -81810, -71914, -52056, -13782, 44240, -30093, -2437, 24007, 67581, -17365, -69164, -8420, -69289, -29370, 48010, 90439, 13141, 69243, 50668, 39328, 61731, 78266, -81313, 17921, -38196, 55261, 9948, -24970, 75712, -72106, 28696, 7461, 31621, 61047, 51476, 56512, 11839, -96916, -82739, 28924, -99927, 58449, 37280, 69357, 11219, -32119, -62050, -48745, -83486, -52376, 42668, 82659, 68882, 38773, 46269, -96005, 97630, 25009, -2951, -67811, 99801, 81587, -79793, -18547, -83086, 69512, 33127, -92145, -88497, 47703, 59527, 1909, 88785, -88882, 69188, -46131, -5589, -15086, 36255, -53238, -33009, 82664, 53901, 35939, -42946, -25571, 33298, 69291, 53199, 74746, -40127, -39050, 91033, 51717, -98048, 87240, 36172, 65453, -94425, -63694, -30027, 59004, 88660, 3649, -20267, -52565, -67321, 34037, 4320, 91515, -56753, 60115, 27134, 68617, -61395, -26503, -98929, -8849, -63318, 10709, -16151, 61905, -95785, 5262, 23670, -25277, 90206, -19391, 45735, 37208, -31992, -92450, 18516, -90452, -58870, -58602, 93383, 14333, 17994, 82411, -54126, -32576, 35440, -60526, -78764, -25069, -9022, -394, 92186, -38057, 55328, -61569, 67780, 77169, 19546, -92664, -94948, 44484, -13439, 83529, 27518, -48333, 72998, 38342, -90553, -98578, -76906, 81515, -16464, 78439, 92529, 35225, -39968, -10130, -7845, -32245, -74955, -74996, 67731, -13897, -82493, 33407, 93619, 59560, -24404, -57553, 19486, -45341, 34098, -24978, -33612, 79058, 71847, 76713, -95422, 6421, -96075, -59130, -28976, -16922, -62203, 69970, 68331, 21874, 40551, 89650, 51908, 58181, 66480, -68177, 34323, -3046, -49656, -59758, 43564, -10960, -30796, 15473, -20216, 46085, -85355, 41515, -30669, -87498, 57711, 56067, 63199, -83805, 62042, 91213, -14606, 4394, -562, 74913, 10406, 96810, -61595, 32564, 31640, -9732, 42058, 98052, -7908, -72330, 1558, -80301, 34878, 32900, 3939, -8824, 88316, 20937, 21566, -3218, -66080, -31620, 86859, 54289, 90476, -42889, -15016, -18838, 75456, 30159, -67101, 42328, -92703, 85850, -5475, 23470, -80806, 68206, 17764, 88235, 46421, -41578, 74005, -81142, 80545, 20868, -1560, 64017, 83784, 68863, -97516, -13016, -72223, 79630, -55692, 82255, 88467, 28007, -34686, -69049, -41677, 88535, -8217, 68060, -51280, 28971, 49088, 49235, 26905, -81117, -44888, 40623, 74337, -24662, 97476, 79542, -72082, -35093, 98175, -61761, -68169, 59697, -62542, -72965, 59883, -64026, -37656, -92392, -12113, -73495, 98258, 68379, -21545, 64607, -70957, -92254, -97460, -63436, -8853, -19357, -51965, -76582, 12687, -49712, 45413, -60043, 33496, 31539, -57347, 41837, 67280, -68813, 52088, -13155, -86430, -15239, -45030, 96041, 18749, -23992, 46048, 35243, -79450, 85425, -58524, 88781, -39454, 53073, -48864, -82289, 39086, 82540, -11555, 25014, -5431, -39585, -89526, 2705, 31953, -81611, 36985, -56022, 68684, -27101, 11422, 64655, -26965, -63081, -13840, -91003, -78147, -8966, 41488, 1988, 99021, -61575, -47060, 65260, -23844, -21781, -91865, -19607, 44808, 2890, 63692, -88663, -58272, 15970, -65195, -45416, -48444, -78226, -65332, -24568, 42833, -1806, -71595, 80002, -52250, 30952, 48452, -90106, 31015, -22073, 62339, 63318, 78391, 28699, 77900, -4026, -76870, -45943, 33665, 9174, -84360, -22684, -16832, -67949, -38077, -38987, -32847, 51443, -53580, -13505, 9344, -92337, 26585, 70458, -52764, -67471, -68411, -1119, -2072, -93476, 67981, 40887, -89304, -12235, 41488, 1454, 5355, -34855, -72080, 24514, -58305, 3340, 34331, 8731, 77451, -64983, -57876, 82874, 62481, -32754, -39902, 22451, -79095, -23904, 78409, -7418, 77916};
    System.out.println(threeSum(nums));
  }
}

16. 3Sum Closest

Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

Example:

Given array nums = [-1, 2, 1, -4], and target = 1.

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
package com.diguage.algorithm.leetcode;

import java.util.Arrays;
import java.util.Objects;

/**
 * = 16. 3Sum Closest
 *
 * https://leetcode.com/problems/3sum-closest/description/[3Sum Closest - LeetCode]
 *
 * Given an array nums of n integers and an integer target, find three integers
 * in nums such that the sum is closest to target. Return the sum of the three
 * integers. You may assume that each input would have exactly one solution.
 *
 * .Example:
 * [source]
 * ----
 * Given array nums = [-1, 2, 1, -4], and target = 1.
 *
 * The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-15 00:55
 */
public class _0016_3SumClosest {
    /**
     * Runtime: 4 ms, faster than 96.20% of Java online submissions for 3Sum Closest.
     *
     * Memory Usage: 36.1 MB, less than 100.00% of Java online submissions for 3Sum Closest.
     */
    public int threeSumClosest(int[] nums, int target) {
        if (Objects.isNull(nums)) {
            return target;
        }
        Arrays.sort(nums);
        int length = nums.length;
        int result = 0;
        int difference = Integer.MAX_VALUE;
        for (int head = 0; head < length; head++) {
            int midd = head + 1;
            int tail = length - 1;
            while (midd < tail) {
                int sum = nums[head] + nums[midd] + nums[tail];
                if (sum > target) {
                    while (midd < tail && nums[tail - 1] == nums[tail]) {
                        tail--;
                    }
                    tail--;
                } else if (sum < target) {
                    while (midd < tail && nums[midd] == nums[midd + 1]) {
                        midd++;
                    }
                    midd++;
                } else {
                    return target;
                }
                int tempDiff = Math.abs(sum - target);
                if (tempDiff < difference) {
                    result = sum;
                    difference = tempDiff;
                }
            }
        }

        return result;
    }


    /**
     * Runtime: 73 ms, faster than 7.18% of Java online submissions for 3Sum Closest.
     *
     * Memory Usage: 36.7 MB, less than 100.00% of Java online submissions for 3Sum Closest.
     */
    public int threeSumClosestO3(int[] nums, int target) {
        if (Objects.isNull(nums)) {
            return target;
        }
        int length = nums.length;
        if (length <= 3) {
            int result = 0;
            for (int i = 0; i < length; i++) {
                result += nums[i];
            }
            return result;
        }

        int result = 0;
        int difference = Integer.MAX_VALUE;

        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                for (int k = j + 1; k < length; k++) {
                    int sum = nums[i] + nums[j] + nums[k];
                    int temp = Math.abs(target - sum);
                    if (temp < difference) {
                        difference = temp;
                        result = sum;
                    }
                }
            }
        }
        return result;
    }

    public static void main(String[] args) {
        _0016_3SumClosest solution = new _0016_3SumClosest();
        int r1 = solution.threeSumClosest(new int[]{-1, 2, 1, -4}, 1);
        System.out.println((2 == r1) + " : " + r1);
    }
}

17. Letter Combinations of a Phone Number

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.

A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

200px Telephone keypad2.svg

Example:

Input: "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

Note:

Although the above answer is in lexicographical order, your answer could be in any order you want.

解题分析

这道题可以使用回溯来解决:每次取出一个数字对应的字母列表,遍历追加到上一次的字母组合中。依次进行,直到数字取完为止。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package com.diguage.algorithm.leetcode;

import java.util.*;

/**
 * = 17. Letter Combinations of a Phone Number
 *
 * https://leetcode.com/problems/letter-combinations-of-a-phone-number/[Letter Combinations of a Phone Number - LeetCode]
 *
 * Given a string containing digits from 2-9 inclusive, return all possible letter
 * combinations that the number could represent.
 *
 * A mapping of digit to letters (just like on the telephone buttons) is given below.
 * Note that 1 does not map to any letters.
 *
 * * 1 - {},
 * * 2 - {'a','b','c'},
 * * 3 - {'d','e','f'},
 * * 4 - {'g','h','i'},
 * * 5 - {'j','k','l'},
 * * 6 - {'m','n','o'},
 * * 7 - {'p','q','r','s'},
 * * 8 - {'t','u','v'},
 * * 9 - {'w','x','y','z'},
 * * 0 - {}
 *
 * .Example:
 * [source]
 * ----
 * Input: "23"
 * Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
 * ----
 *
 * *Note:*
 *
 * Although the above answer is in lexicographical order, your answer could be in any order you want.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-19 00:19
 */
public class _0017_LetterCombinationsOfAPhoneNumber {

  private List<String> result = new ArrayList<>();
  public List<String> letterCombinations(String digits) {
    if (Objects.isNull(digits) || digits.length() == 0) {
      return result;
    }
    backtrack(digits, "");
    return result;
  }
  private void backtrack(String digits, String letters) {
    if (digits.length() == 0) {
      result.add(letters);
      return;
    }
    String let = getLetterByChar(digits.charAt(0));
    String sub = digits.substring(1);
    if (let.length() > 0) {
      for (int i = 0; i < let.length(); i++) {
        backtrack(sub, letters + let.charAt(i));
      }
    } else {
      backtrack(sub, letters);
    }
  }

  private String getLetterByChar(char c) {
    switch (c) {
      case '2':
        return "abc";
      case '3':
        return "def";
      case '4':
        return "ghi";
      case '5':
        return "jkl";
      case '6':
        return "mno";
      case '7':
        return "pqrs";
      case '8':
        return "tuv";
      case '9':
        return "wxyz";
      default:
        return "";
    }
  }

  /**
   * Runtime: 32 ms, faster than 6.94% of Java online submissions for Letter Combinations of a Phone Number.
   *
   * Memory Usage: 36.2 MB, less than 99.10% of Java online submissions for Letter Combinations of a Phone Number.
   */
  public List<String> letterCombinations1(String digits) {
    if (Objects.isNull(digits) || digits.length() == 0) {
      return Collections.EMPTY_LIST;
    }

    char[] chars = digits.toCharArray();
    List<Integer> integers = new ArrayList<>();
    int length = chars.length;
    for (int i = 0; i < length; i++) {
      int num = chars[i] - '0';
      if (num > 1) {
        integers.add(num);
      }
    }
    char[][] int2chars = new char[][]{
      {},
      {},
      {'a', 'b', 'c'},
      {'d', 'e', 'f'},
      {'g', 'h', 'i'},
      {'j', 'k', 'l'},
      {'m', 'n', 'o'},
      {'p', 'q', 'r', 's'},
      {'t', 'u', 'v'},
      {'w', 'x', 'y', 'z'},
    };
    int size = integers.size();
    char[][] selectedChars = new char[size][];
    for (int i = 0; i < size; i++) {
      selectedChars[i] = int2chars[integers.get(i)];
    }

    return combine(selectedChars, 0);
  }

  public List<String> combine(char[][] chars, int depth) {
    List<String> result = new ArrayList<>();
    char[] rowChars = chars[depth];
    if (depth == chars.length - 1) {
      for (int i = 0; i < rowChars.length; i++) {
        result.add(rowChars[i] + "");
      }
    } else {
      List<String> strings = combine(chars, depth + 1);
      for (int i = 0; i < rowChars.length; i++) {
        char aChar = rowChars[i];
        strings.forEach(s -> result.add(aChar + s));
      }
    }
    return result;
  }


  public static void main(String[] args) {
    _0017_LetterCombinationsOfAPhoneNumber solution = new _0017_LetterCombinationsOfAPhoneNumber();
    List<String> r1 = solution.letterCombinations("23");
    Collections.sort(r1);
    System.out.println(Arrays.toString(r1.toArray(new String[0])));
    List<String> s1 = Arrays.asList("ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf");
    Collections.sort(s1);
    System.out.println(s1.equals(r1) + " : " + Arrays.toString(r1.toArray(new String[0])));
  }

}

18. 4Sum

Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

The solution set must not contain duplicate quadruplets.

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
package com.diguage.algorithm.leetcode;

import java.util.*;

/**
 * = 18. 4Sum
 *
 * https://leetcode.com/problems/4sum/description/[4Sum - LeetCode]
 *
 * Given an array `nums` of n integers and an integer `target`, are there
 * elements `a`, `b`, `c`, and `d` in `nums` such that `a + b + c + d = target`?
 * Find all unique quadruplets in the array which gives the sum of target.
 *
 * == Note
 *
 * The solution set must not contain duplicate quadruplets.
 *
 * .Example:
 * [source]
 * ----
 * Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.
 *
 * A solution set is:
 * [
 *   [-1,  0, 0, 1],
 *   [-2, -1, 1, 2],
 *   [-2,  0, 0, 2]
 * ]
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-15 00:58
 */
public class _0018_4Sum {
    /**
     * Runtime: 4 ms, faster than 94.46% of Java online submissions for 4Sum.
     *
     * Memory Usage: 40.7 MB, less than 52.17% of Java online submissions for 4Sum.
     */
    public List<List<Integer>> fourSum(int[] nums, int target) {
        int numCount = 4;
        if (Objects.isNull(nums) || nums.length < numCount) {
            return Collections.emptyList();
        }

        Arrays.sort(nums);
        int length = nums.length;
        if (target < numCount * nums[0] || numCount * nums[length - 1] < target) {
            return Collections.emptyList();
        }

        List<List<Integer>> result = new LinkedList<>();
        for (int i = 0; i < length - 3; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            for (int j = i + 1; j < length - 2; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                int twoSumTarget = target - nums[i] - nums[j];
                int minTwoSum = nums[j + 1] + nums[j + 2];
                int maxTwoSum = nums[length - 1] + nums[length - 2];
                if (twoSumTarget < minTwoSum || maxTwoSum < twoSumTarget) {
                    continue;
                }
                for (int m = j + 1, n = length - 1; m < n; ) {
                    int twoSum = nums[m] + nums[n];
                    if (twoSum < twoSumTarget) {
                        while (m < n && nums[m] == nums[m + 1]) {
                            m++;
                        }
                        m++;
                    } else if (twoSumTarget < twoSum) {
                        while (m < n && nums[n - 1] == nums[n]) {
                            n--;
                        }
                        n--;
                    } else {
                        result.add(Arrays.asList(nums[i], nums[j], nums[m], nums[n]));

                        while (m < n && nums[m] == nums[m + 1]) {
                            m++;
                        }
                        m++;

                        while (m < n && nums[n - 1] == nums[n]) {
                            n--;
                        }
                        n--;
                    }
                }
            }
        }

        return result;
    }

    public static void main(String[] args) {
        _0018_4Sum solution = new _0018_4Sum();
        List<List<Integer>> r1 = solution.fourSum(new int[]{1, 0, -1, 0, -2, 2}, 0);
        System.out.println(Arrays.deepToString(r1.toArray()));
    }
}

19. Remove Nth Node From End of List

Given a linked list, remove the n-th node from the end of list and return its head.

Example:

Given linked list: 1->2->3->4->5, and n = 2.

After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Follow up:

Could you do this in one pass?

解题分析

快慢指针

0019 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.diguage.algorithm.leetcode;

import com.diguage.algorithm.util.ListNode;

import java.util.Arrays;
import java.util.Objects;

import static com.diguage.algorithm.util.ListNodeUtils.build;
import static com.diguage.algorithm.util.ListNodeUtils.printListNode;

/**
 * = 19. Remove Nth Node From End of List
 *
 * https://leetcode.com/problems/remove-nth-node-from-end-of-list/[Remove Nth Node From End of List - LeetCode]
 *
 * Given a linked list, remove the n-th node from the end of list and return its head.
 *
 * .Example 1:
 * [source]
 * ----
 * Given linked list: 1->2->3->4->5, and n = 2.
 *
 * After removing the second node from the end, the linked list becomes 1->2->3->5.
 * ----
 *
 * *Note:*
 *
 * Given n will always be valid.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-26 20:17
 */
public class _0019_RemoveNthNodeFromEndOfList {
    /**
     * Runtime: 0 ms, faster than 100.00% of Java online submissions for Remove Nth Node From End of List.
     *
     * Memory Usage: 34.6 MB, less than 100.00% of Java online submissions for Remove Nth Node From End of List.
     */
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (Objects.isNull(head) || n == 0) {
            return head;
        }
        ListNode p1 = head;
        int length = 1;
        while (Objects.nonNull(p1.next) && length <= n) {
            p1 = p1.next;
            length++;
        }
        if (Objects.isNull(p1.next) && length == n) {
            return head.next;
        }
        if (Objects.isNull(p1.next) && length < n) {
            return head;
        }

        ListNode p2 = head;
        while (Objects.nonNull(p1.next)) {
            p1 = p1.next;
            p2 = p2.next;
        }
        if (Objects.nonNull(p2.next)) {
            p2.next = p2.next.next;
        }
        return head;
    }

    public static void main(String[] args) {
        _0019_RemoveNthNodeFromEndOfList solution = new _0019_RemoveNthNodeFromEndOfList();

        ListNode r5 = solution.removeNthFromEnd(build(Arrays.asList(1, 2)), 1);
        printListNode(r5);

        ListNode r4 = solution.removeNthFromEnd(build(Arrays.asList(1)), 1);
        printListNode(r4);

        ListNode r1 = solution.removeNthFromEnd(build(Arrays.asList(1, 2, 3, 4, 5)), 2);
        printListNode(r1);

        ListNode r2 = solution.removeNthFromEnd(build(Arrays.asList(1, 2, 3, 4, 5)), 6);
        printListNode(r2);

        ListNode r3 = solution.removeNthFromEnd(build(Arrays.asList()), 2);
        printListNode(r3);
    }
}

20. Valid Parentheses

Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.

An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.

  2. Open brackets must be closed in the correct order.

Note that an empty string is also considered valid.

Example 1:

Input: "()"
Output: true

Example 2:

Input: "()[]{}"
Output: true

Example 3:

Input: "(]"
Output: false

Example 4:

Input: "([)]"
Output: false

Example 5:

Input: "{[]}"
Output: true
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package com.diguage.algorithm.leetcode;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Stack;

/**
 * = 20. Valid Parentheses
 *
 * https://leetcode.com/problems/valid-parentheses/[Valid Parentheses - LeetCode]
 *
 * Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
 *
 * An input string is valid if:
 *
 * Open brackets must be closed by the same type of brackets.
 * Open brackets must be closed in the correct order.
 * Note that an empty string is also considered valid.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: "()"
 * Output: true
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: "()[]{}"
 * Output: true
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: "(]"
 * Output: false
 * ----
 *
 * .Example 4:
 * [source]
 * ----
 * Input: "([)]"
 * Output: false
 * ----
 *
 * .Example 5:
 * [source]
 * ----
 * Input: "{[]}"
 * Output: true
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-26 08:12
 */
public class _0020_ValidParentheses {
    /**
     * Runtime: 2 ms, faster than 60.99% of Java online submissions for Valid Parentheses.
     *
     * Memory Usage: 34.2 MB, less than 100.00% of Java online submissions for Valid Parentheses.
     */
    public boolean isValid(String s) {
        if (Objects.isNull(s) || s.length() == 0) {
            return true;
        }
        Map<Character, Character> parenthesesMap = new HashMap<>(3);
        parenthesesMap.put('(', ')');
        parenthesesMap.put('{', '}');
        parenthesesMap.put('[', ']');
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char aChar = s.charAt(i);
            if (parenthesesMap.containsKey(aChar)) {
                stack.push(aChar);
            } else {
                if (stack.isEmpty()) {
                    return false;
                }
                char peek = stack.pop();
                if (aChar != parenthesesMap.get(peek)) {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }

    public static void main(String[] args) {
        _0020_ValidParentheses solution = new _0020_ValidParentheses();

        String s7 = "[";
        boolean valid7 = solution.isValid(s7);
        System.out.println((false == valid7) + " : " + s7);

        String s6 = "]";
        boolean valid6 = solution.isValid(s6);
        System.out.println((false == valid6) + " : " + s6);

        String s1 = "()";
        boolean valid1 = solution.isValid(s1);
        System.out.println((true == valid1) + " : " + s1);

        String s2 = "()[]{}";
        boolean valid2 = solution.isValid(s2);
        System.out.println((true == valid2) + " : " + s2);

        String s3 = "(]";
        boolean valid3 = solution.isValid(s3);
        System.out.println((false == valid3) + " : " + s3);

        String s4 = "([)]";
        boolean valid4 = solution.isValid(s4);
        System.out.println((false == valid4) + " : " + s4);

        String s5 = "{[]}";
        boolean valid5 = solution.isValid(s5);
        System.out.println((true == valid5) + " : " + s5);
    }
}

21. Merge Two Sorted Lists

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

Example:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
package com.diguage.algorithm.leetcode;

import com.diguage.algorithm.util.ListNode;

import java.util.Arrays;
import java.util.Objects;

import static com.diguage.algorithm.util.ListNodeUtils.build;
import static com.diguage.algorithm.util.ListNodeUtils.isOrder;

/**
 * = 21. Merge Two Sorted Lists
 *
 * https://leetcode.com/problems/merge-two-sorted-lists/[Merge Two Sorted Lists - LeetCode]
 *
 * Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
 *
 * .Example:
 * [source]
 * ----
 * Input: 1->2->4, 1->3->4
 * Output: 1->1->2->3->4->4
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-26 08:49
 */
public class _0021_MergeTwoSortedLists {
  public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    if (Objects.isNull(l1) && Objects.isNull(l2)) {
      return null;
    }
    ListNode dummy = new ListNode();
    ListNode tail = dummy;
    while (Objects.nonNull(l1) && Objects.nonNull(l2)) {
      if (l1.val < l2.val) {
        tail.next = l1;
        l1 = l1.next;
      } else {
        tail.next = l2;
        l2 = l2.next;
      }
      tail = tail.next;
    }
    if (Objects.isNull(l1)) {
      tail.next = l2;
    }
    if (Objects.isNull(l2)) {
      tail.next = l1;
    }
    return dummy.next;
  }

  /**
   * Runtime: 1 ms, faster than 28.15% of Java online submissions for Merge Two Sorted Lists.
   *
   * Memory Usage: 39.8 MB, less than 14.45% of Java online submissions for Merge Two Sorted Lists.
   */
  public ListNode mergeTwoLists1(ListNode l1, ListNode l2) {
    if (Objects.isNull(l1)) {
      return l2;
    }
    if (Objects.isNull(l2)) {
      return l1;
    }
    ListNode result = null;
    ListNode p1 = l1;
    ListNode p2 = l2;
    ListNode tail = null;

    while (Objects.nonNull(p1) && Objects.nonNull(p2)) {
      int v1 = p1.val;
      int v2 = p2.val;
      ListNode temp = null;
      if (v1 < v2) {
        temp = p1;
        p1 = p1.next;
      } else {
        temp = p2;
        p2 = p2.next;
      }
      if (Objects.isNull(tail)) {
        result = temp;
        tail = temp;
      } else {
        tail.next = temp;
        tail = temp;
      }
    }
    if (Objects.isNull(p1)) {
      tail.next = p2;
    }

    if (Objects.isNull(p2)) {
      tail.next = p1;
    }

    return result;
  }

  public static void main(String[] args) {
    _0021_MergeTwoSortedLists solution = new _0021_MergeTwoSortedLists();
    ListNode l1 = build(Arrays.asList());
    ListNode l2 = build(Arrays.asList());
    ListNode r1 = solution.mergeTwoLists(l1, l2);
    System.out.println(isOrder(r1));
  }
}

22. Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

[
  "",
  ")(",
  "))()",   "()((",
  "()()()"
]

解题分析

0022 mindmap

使用回溯法解题时,需要关注的一个点是,在递归调用时,为了保证结果是有效的括号对,则添加的闭区间符号不能多于开区间符号。也就是,保证添加在添加一个闭区间符号之前,要先添加了对应的开区间符号。所以,就要注意闭区间的判断,是跟开区间大小判断,而不是括号数量。并不是所有的排列组合都符合我们的需求。

0022 0
0022 1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.diguage.algorithm.leetcode;


import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

/**
 * = 22. Generate Parentheses
 *
 * Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
 *
 * For example, given n = 3, a solution set is:
 *
 * ----
 * [
 *   "((()))",
 *   "(()())",
 *   "(())()",
 *   "()(())",
 *   "()()()"
 * ]
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-27 08:11
 */
public class _0022_GenerateParentheses {
  /**
   * Runtime: 2 ms, faster than 21.88% of Java online submissions for Generate Parentheses.
   *
   * Memory Usage: 45.3 MB, less than 5.16% of Java online submissions for Generate Parentheses.
   *
   * Copy from: https://leetcode.com/problems/generate-parentheses/solution/[Generate Parentheses solution - LeetCode]
   */
  public List<String> generateParenthesis(int n) {
    List<String> ans = new LinkedList<>();
    backtrack(ans, "", 0, 0, n);
    return ans;
  }

  public void backtrack(List<String> result, String curr, int open, int close, int n) {
    if (curr.length() == 2 * n) {
      result.add(curr);
      return;
    }
    if (open < n) {
      backtrack(result, curr + "(", open + 1, close, n);
    }
    if (close < open) {
      backtrack(result, curr + ")", open, close + 1, n);
    }
  }


  public static void main(String[] args) {
    _0022_GenerateParentheses solution = new _0022_GenerateParentheses();

    List<String> r3 = solution.generateParenthesis(3);
    r3.sort(Comparator.naturalOrder());
    List<String> p3 = Arrays.asList("((()))", "(()())", "(())()", "()(())", "()()()");
    p3.sort(Comparator.naturalOrder());
    System.out.println("▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽");
    System.out.println((p3.equals(r3)) + " : \n"
      + Arrays.toString(r3.toArray(new String[0])) + "\n"
      + Arrays.toString(p3.toArray(new String[0])));
    System.out.println("△△△△△△△△△△△△△△△△△△△△");

    List<String> r4 = solution.generateParenthesis(4);
    r4.sort(Comparator.naturalOrder());
    List<String> p4 = Arrays.asList("(((())))", "((()()))", "((())())", "((()))()", "(()(()))", "(()()())", "(()())()", "(())(())", "(())()()", "()((()))", "()(()())", "()(())()", "()()(())", "()()()()");
    p4.sort(Comparator.naturalOrder());
    System.out.println("▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽");
    System.out.println((p4.equals(r4)) + " : \n"
      + Arrays.toString(r4.toArray(new String[0])) + "\n"
      + Arrays.toString(p4.toArray(new String[0])));
    System.out.println("△△△△△△△△△△△△△△△△△△△△");
  }
}

思考题

有机会思考尝试一下广度优先遍历。

23. Merge k Sorted Lists

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

Example:

Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package com.diguage.algorithm.leetcode;

import java.util.*;

import com.diguage.algorithm.util.ListNode;

import static com.diguage.algorithm.util.ListNodeUtils.*;

/**
 * = 23. Merge k Sorted Lists
 *
 * https://leetcode.com/problems/merge-k-sorted-lists/[(8) Merge k Sorted Lists - LeetCode]
 *
 * Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
 *
 * .Example:
 * [source]
 * ----
 * Input:
 * [
 *   1->4->5,
 *   1->3->4,
 *   2->6
 * ]
 * Output: 1->1->2->3->4->4->5->6
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-10-22 12:40:12
 */
public class _0023_MergeKSortedLists {

  public ListNode mergeKLists(ListNode[] lists) {
    PriorityQueue<ListNode> heap = new PriorityQueue<>((l1, l2) -> l1.val - l2.val);
    for (ListNode l : lists) {
      if (Objects.nonNull(l)) {
        heap.add(l);
      }
    }
    ListNode dummy = new ListNode();
    ListNode curr = dummy;
    while (!heap.isEmpty()) {
      ListNode node = heap.poll();
      curr.next = node;
      curr = curr.next;
      if (Objects.nonNull(node.next)) {
        heap.add(node.next);
      }
    }
    return dummy.next;
  }

  /**
   * Runtime: 40 ms, faster than 20.21% of Java online submissions for Merge k Sorted Lists.
   *
   * Memory Usage: 39.6 MB, less than 74.87% of Java online submissions for Merge k Sorted Lists.
   */
  public ListNode mergeKLists1(ListNode[] lists) {
    PriorityQueue<ListNode> queue = new PriorityQueue<>(Comparator.comparingInt(o -> o.val));
    for (ListNode list : lists) {
      if (Objects.nonNull(list)) {
        queue.add(list);
      }
    }

    ListNode result = null;
    ListNode tail = null;
    for (ListNode node = queue.poll(); Objects.nonNull(node); ) {
      if (Objects.isNull(result)) {
        result = node;
      }
      ListNode next = node.next;
      if (Objects.nonNull(next)) {
        queue.add(next);
      }
      if (Objects.nonNull(tail)) {
        tail.next = node;
      }
      tail = node;
      node = queue.poll();
    }

    return result;
  }

  public static void main(String[] args) {
    ListNode node1 = build(Arrays.asList(1, 4, 5));
    ListNode node2 = build(Arrays.asList(1, 3, 4));
    ListNode node3 = build(Arrays.asList(2, 6));
    ListNode[] lists = new ListNode[]{node1, node2, node3};
    _0023_MergeKSortedLists solution = new _0023_MergeKSortedLists();
    ListNode r1 = solution.mergeKLists(lists);
    System.out.println(isOrder(r1));
  }
}

24. Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list’s nodes, only nodes itself may be changed.

Example:
Given 1->2->3->4, you should return the list as 2->1->4->3.

思考题

尝试使用递归来实现一下。

参考资料

Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list’s nodes, only nodes itself may be changed.

Example:

Given 1->2->3->4, you should return the list as 2->1->4->3.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.diguage.algorithm.leetcode;

import com.diguage.algorithm.util.ListNode;

import java.util.Objects;

import static com.diguage.algorithm.util.ListNodeUtils.build;
import static com.diguage.algorithm.util.ListNodeUtils.printListNode;
import static java.util.Arrays.asList;

/**
 * = 24. Swap Nodes in Pairs
 *
 * https://leetcode.com/problems/swap-nodes-in-pairs/[Swap Nodes in Pairs - LeetCode]
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-02-03 20:12
 */
public class _0024_SwapNodesInPairs {
    /**
     * Runtime: 0 ms, faster than 100.00% of Java online submissions for Swap Nodes in Pairs.
     * Memory Usage: 37.3 MB, less than 5.50% of Java online submissions for Swap Nodes in Pairs.
     */
    public ListNode swapPairs(ListNode head) {
        if (Objects.isNull(head) || Objects.isNull(head.next)) {
            return head;
        }
        ListNode result = head.next;
        ListNode prevNode = new ListNode(0);
        prevNode.next = head;
        while (Objects.nonNull(head) && Objects.nonNull(head.next)) {
            ListNode second = head.next;
            head.next = second.next;
            second.next = head;
            prevNode.next = second;
            prevNode = head;
            head = head.next;
        }

        return result;
    }

    public static void main(String[] args) {
        _0024_SwapNodesInPairs solution = new _0024_SwapNodesInPairs();
        ListNode r1 = solution.swapPairs(build(asList(1, 2, 3, 4)));
        printListNode(r1);
    }
}

25. Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

Example:

Given this linked list: 1→2→3→4→5

For k = 2, you should return: 2→1→4→3→5

For k = 3, you should return: 3→2→1→4→5

Note:

  • Only constant extra memory is allowed.

  • You may not alter the values in the list’s nodes, only nodes itself may be changed.

1
Unresolved directive in 0025-reverse-nodes-in-k-group.adoc - include::/home/runner/work/leetcode/leetcode/src/main/java/com/diguage/algorithm/leetcode/_0025_ReverseNodesInKGroup.java[]

26. Remove Duplicates from Sorted Array

Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

Example 1:

Given nums = [1,1,2],

Your function should return length = 2, with the first two elements of `nums` being 1 and 2 respectively.

It doesn't matter what you leave beyond the returned length.

Example 2:

Given nums = [0,0,1,1,1,2,2,3,3,4],

Your function should return length = 5, with the first five elements of `nums` being modified to 0, 1, 2, 3, and 4 respectively.

It doesn't matter what values are set beyond the returned length.

Clarification:

Confused why the returned value is an integer but your answer is an array?

Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.

Internally you can think of this:

// nums is passed in by reference. (i.e., without making a copy)
int len = removeDuplicates(nums);

// any modification to nums in your function would be known by the caller.
// using the length returned by your function, it prints the first len elements.
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

解题分析

把后面的数据向前拷贝。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
package com.diguage.algorithm.leetcode;

import java.util.Arrays;
import java.util.Objects;

/**
 * = 26. Remove Duplicates from Sorted Array
 *
 * https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/[Remove Duplicates from Sorted Array - LeetCode]
 *
 * Given a sorted array `nums`, remove the duplicates
 * *https://en.wikipedia.org/wiki/In-place_algorithm[in-place]* such that each
 * element appear only once and return the new length.
 *
 * Do not allocate extra space for another array, you must do this by *modifying
 * the input array* *https://en.wikipedia.org/wiki/In-place_algorithm[in-place]*
 * with O(1) extra memory.
 *
 * .Example 1:
 * [source]
 * ----
 * Given nums = [1,1,2],
 *
 * Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
 *
 * It doesn't matter what you leave beyond the returned length.
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Given nums = [0,0,1,1,1,2,2,3,3,4],
 *
 * Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.
 *
 * It doesn't matter what values are set beyond the returned length.
 * ----
 *
 * == Clarification
 *
 * Confused why the returned value is an integer but your answer is an array?
 *
 * Note that the input array is passed in by *reference*, which means modification to the input array will be known to the caller as well.
 *
 * Internally you can think of this:
 *
 * [source]
 * ----
 * // nums is passed in by reference. (i.e., without making a copy)
 * int len = removeDuplicates(nums);
 *
 * // any modification to nums in your function would be known by the caller.
 * // using the length returned by your function, it prints the first len elements.
 * for (int i = 0; i < len; i++) {
 * print(nums[i]);
 * }
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-19 18:34
 */
public class _0026_RemoveDuplicatesFromSortedArray {
  public static int removeDuplicates(int[] nums) {
    if (Objects.isNull(nums) || nums.length == 0) {
      return 0;
    }
    int i = 0;
    for (int j = 1; j < nums.length; j++) {
      if (nums[i] != nums[j]) {
        i++;
        nums[i] = nums[j];
      }
    }
    return i + 1;
  }

  public static int removeDuplicates1(int[] nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }
    int result = nums.length;
    if (nums.length == 1) {
      return result;
    }

    int previousNum = nums[0];
    int minuendIndex = 0;
    for (int i = 1; i < nums.length; i++) {
      if (previousNum == nums[i]) {
        minuendIndex++;
        result--;
      } else {
        previousNum = nums[i];
      }
      if (minuendIndex > 0) {
        nums[i - minuendIndex] = nums[i];
      }
    }

    return result;
  }

  public static void main(String[] args) {
    int[] nums = {1, 2, 2};
    System.out.println(removeDuplicates(nums));
    System.out.println(Arrays.toString(nums));
  }
}

27. Remove Element

Given an array nums and a value val, remove all instances of that value in-place and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

The order of elements can be changed. It doesn’t matter what you leave beyond the new length.

Example 1:

Given nums = [3,2,2,3], val = 3,

Your function should return length = 2, with the first two elements of nums being 2.

It doesn't matter what you leave beyond the returned length.

Example 2:

Given nums = [0,1,2,2,3,0,4,2], val = 2,

Your function should return length = 5, with the first five elements of `nums` containing 0, 1, 3, 0, and 4.

Note that the order of those five elements can be arbitrary.

It doesn't matter what values are set beyond the returned length.

Clarification:

Confused why the returned value is an integer but your answer is an array?

Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.

Internally you can think of this:

// nums is passed in by reference. (i.e., without making a copy)
int len = removeElement(nums, val);

// any modification to nums in your function would be known by the caller.
// using the length returned by your function, it prints the first len elements.
for (int i = 0; i < len; i++) {
    print(nums[i]);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.diguage.algorithm.leetcode;

import java.util.Arrays;

/**
 * = 27. Remove Element
 *
 * https://leetcode.com/problems/remove-element/description/[Remove Element - LeetCode]
 *
 * Given an array `nums` and a value `val`, remove all instances of that value
 * *https://en.wikipedia.org/wiki/In-place_algorithm[in-place]* and return the new length.
 *
 * Do not allocate extra space for another array, you must do this by *modifying
 * the input array* *https://en.wikipedia.org/wiki/In-place_algorithm[in-place]* with O(1) extra memory.
 *
 * The order of elements can be changed. It doesn't matter what you leave beyond the new length.
 *
 * .Example 1:
 * [source]
 * ----
 * Given nums = [3,2,2,3], val = 3,
 *
 * Your function should return length = 2, with the first two elements of nums being 2.
 *
 * It doesn't matter what you leave beyond the returned length.
 * ----
 *
 * .Example 1:
 * [source]
 * ----
 * Given nums = [0,1,2,2,3,0,4,2], val = 2,
 *
 * Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4.
 *
 * Note that the order of those five elements can be arbitrary.
 *
 * It doesn't matter what values are set beyond the returned length.
 * ----
 *
 * == Clarification:
 *
 * Confused why the returned value is an integer but your answer is an array?
 *
 * Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.
 *
 * Internally you can think of this:
 *
 * [source]
 * ----
 * // nums is passed in by reference. (i.e., without making a copy)
 * int len = removeElement(nums, val);
 *
 * // any modification to nums in your function would be known by the caller.
 * // using the length returned by your function, it prints the first len elements.
 * for (int i = 0; i < len; i++) {
 *     print(nums[i]);
 * }
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-19 18:55
 */
public class _0027_RemoveElement {
    public static int removeElement(int[] nums, int val) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int result = nums.length;
        int minuendIndex = 0;
        for (int i = 0; i < nums.length; i++) {
            if (minuendIndex > 0) {
                nums[i - minuendIndex] = nums[i];
            }
            if (nums[i] == val) {
                result--;
                minuendIndex++;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[] nums = new int[]{0, 1, 2, 2, 3, 0, 4, 2};
        int val = 2;
        System.out.println(removeElement(nums, val));
        System.out.println(Arrays.toString(nums));
    }
}

28. Implement strStr()

Implement strStr().

Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

Example 1:

Input: haystack = "hello", needle = "ll"
Output: 2

Example 2:

Input: haystack = "aaaaa", needle = "bba"
Output: -1

Clarification:

What should we return when needle is an empty string? This is a great question to ask during an interview.

For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C’s strstr() and Java’s indexOf().

解题分析

直接截取字符串然后判断相等,算不算作弊?😆

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 28. Implement strStr()
 *
 * Implement `strStr()`.
 *
 * Return the index of the first occurrence of needle in haystack, or *-1* if needle is not part of haystack.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: haystack = "hello", needle = "ll"
 * Output: 2
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: haystack = "aaaaa", needle = "bba"
 * Output: -1
 * ----
 *
 * *Clarification:*
 *
 * What should we return when `needle` is an empty string? This is a great question to ask during an interview.
 *
 * For the purpose of this problem, we will return 0 when `needle` is an empty string. This is consistent to C's `strstr()`
 * and Java's `indexOf()`.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018
 */
public class _0028_ImplementStrStr {
  public int strStr(String haystack, String needle) {
    if (Objects.isNull(needle) || needle.length() == 0) {
      return 0;
    }
    for (int i = 0; i <= haystack.length() - needle.length(); i++) {
      if (haystack.charAt(i) == needle.charAt(0)) {
        String sub = haystack.substring(i, i + needle.length());
        if (needle.equals(sub)) {
          return i;
        }
      }
    }
    return -1;
  }

  // TODO 有必要学一下 KMP 算法了啊!
  public int strStr1(String source, String target) {
    if (source == null || target == null || target.length() > source.length()) {
      return -1;
    }
    if (target.length() == 0) {
      return 0;
    }
    char[] sA = source.toCharArray();
    char[] tA = target.toCharArray();
    for (int i = 0; i < source.length(); i++) {
      if (contain(sA, i, tA)) {
        return i;
      }
    }
    return -1;
  }

  private boolean contain(char[] source, int index, char[] target) {
    if (source.length - index < target.length) {
      return false;
    }
    for (int i = index, j = 0; j < target.length; i++, j++) {
      if (source[i] != target[j]) {
        return false;
      }
    }
    return true;
  }

  public static void main(String[] args) {
    _0028_ImplementStrStr result = new _0028_ImplementStrStr();
    System.out.println(result.strStr("a", "a"));
    System.out.println(result.strStr("hello", "ll"));
    System.out.println(result.strStr("aaaaa", "bba"));
  }
}

29. Divide Two Integers

Given two integers dividend and divisor, divide two integers without using multiplication, division and mod operator.

Return the quotient after dividing dividend by divisor.

The integer division should truncate toward zero.

Example 1:

Input: dividend = 10, divisor = 3
Output: 3

Example 2:

Input: dividend = 7, divisor = -3
Output: -2

Note:

  • Both dividend and divisor will be 32-bit signed integers.

  • The divisor will never be 0.

  • Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [-231, 231 - 1]. For the purpose of this problem, assume that your function returns 231 - 1 when the division result overflows.

解题分析

思路其实挺简单,就是通过移位操作,把被除数不断翻倍到仅次于被除数的倍数,然后从被除数中减去这个值,剩下的部分再反复执行这个操作,直到被除数小于除数为止。

模仿这个思路 C++ bit manipulations - LeetCode Discuss 来实现的。

15 line easy understand solution. 129ms - LeetCode Discuss 这个思路也很棒。它并没有等把倍数计算到最大去减少,而是在翻倍过程中,每次都去减少;等翻倍太大,再以此"减半"。感觉效率更高!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package com.diguage.algorithm.leetcode;

/**
 * = 29. Divide Two Integers
 *
 * https://leetcode.com/problems/divide-two-integers/[Divide Two Integers - LeetCode]
 *
 * Given two integers `dividend` and `divisor`, divide two integers without using multiplication, division and mod operator.
 *
 * Return the quotient after dividing `dividend` by `divisor`.
 *
 * The integer division should truncate toward zero.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: dividend = 10, divisor = 3
 * Output: 3
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: dividend = 7, divisor = -3
 * Output: -2
 * ----
 *
 * *Note:*
 *
 * * Both dividend and divisor will be 32-bit signed integers.
 * * The divisor will never be 0.
 * * Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31^,  2^31^ − 1]. For the purpose of this problem, assume that your function returns 2^31^ − 1 when the division result overflows.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-14 16:46
 */
public class _0029_DivideTwoIntegers {
    /**
     * Runtime: 1 ms, faster than 100.00% of Java online submissions for Divide Two Integers.
     *
     * Memory Usage: 34.3 MB, less than 6.06% of Java online submissions for Divide Two Integers.
     *
     * Copy from: https://leetcode.com/problems/divide-two-integers/discuss/13407/C%2B%2B-bit-manipulations[C++ bit manipulations - LeetCode Discuss]
     */
    public int divide(int dividend, int divisor) {
        if (dividend == Integer.MIN_VALUE && divisor == -1) {
            return Integer.MAX_VALUE;
        }

        int sign = dividend > 0 ^ divisor > 0 ? -1 : 1;
        long ldividend = Math.abs((long) dividend);
        long ldivisor = Math.abs((long) divisor);
        int result = 0;
        while (ldividend >= ldivisor) {
            long temp = ldivisor;
            int mul = 1;
            while (temp << 1 <= ldividend) {
                temp <<= 1;
                mul <<= 1;
            }
            ldividend -= temp;
            result += mul;
        }
        return result * sign;
    }

    public static void main(String[] args) {
        _0029_DivideTwoIntegers solution = new _0029_DivideTwoIntegers();
        int r1 = solution.divide(10, 3);
        System.out.println((r1 == 3) + " : " + r1);

        int r2 = solution.divide(7, -3);
        System.out.println((r2 == -2) + " : " + r2);

        int r3 = solution.divide(2147483647, 1);
        System.out.println((r3 == 2147483647) + " : " + r3);

        int r4 = solution.divide(2147483647, 2);
        System.out.println((r4 == 1073741823) + " : " + r4);
    }
}

30. Substring with Concatenation of All Words

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.

Example 1:

Input:
  s = "barfoothefoobarman",
*  words = ["foo","bar"]
*Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are "barfoo" and "foobar" respectively.
The output order does not matter, returning [9,0] is fine too.

Example 2:

Input:
  s = "wordgoodgoodgoodbestword",
*  words = ["word","good","best","word"]
*Output: []
1
Unresolved directive in 0030-substring-with-concatenation-of-all-words.adoc - include::/home/runner/work/leetcode/leetcode/src/main/java/com/diguage/algorithm/leetcode/_0030_SubstringWithConcatenationOfAllWords.java[]

31. Next Permutation

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place and use only constant extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.

1,2,31,3,2

3,2,11,2,3

1,1,51,5,1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.diguage.algorithm.leetcode;

import java.util.Arrays;
import java.util.Objects;

/**
 * = 31. Next Permutation
 *
 * https://leetcode.com/problems/next-permutation/description/[Next Permutation - LeetCode]
 *
 * Implement *next permutation*, which rearranges numbers into the
 * lexicographically next greater permutation of numbers.
 *
 * If such arrangement is not possible, it must rearrange it as the lowest
 * possible order (ie, sorted in ascending order).
 *
 * The replacement must be
 * *https://en.wikipedia.org/wiki/In-place_algorithm[in-place]* and use only
 * constant extra memory.
 *
 * Here are some examples. Inputs are in the left-hand column and its corresponding
 * outputs are in the right-hand column.
 *
 * `1,2,3` → `1,3,2` +
 * `3,2,1` → `1,2,3` +
 * `1,1,5` → `1,5,1`
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-07-15 01:12
 */
public class _0031_NextPermutation {
    public static void nextPermutation(int[] nums) {
        if (nums == null || nums.length < 2) {
            return;
        }

        for (int i = nums.length - 1; i > 0; i--) {
            if (nums[i - 1] < nums[i]) {
                int temp = nums[i - 1];
                nums[i - 1] = nums[i];
                nums[i] = temp;
                return;
            }
        }
        Arrays.sort(nums);
    }

    public static void main(String[] args) {
        int[] a1 = new int[]{1, 2, 3};
        nextPermutation(a1);
        System.out.println(Arrays.toString(a1));


        int[] a2 = new int[]{3, 2, 1};
        nextPermutation(a2);
        assert !Objects.equals(a2, new int[]{1, 2, 3});
        System.out.println(Arrays.toString(a2));

        int[] a3 = new int[]{1, 1, 5};
        nextPermutation(a3);
        assert !Objects.equals(a3, new int[]{1, 5, 1});
        System.out.println(Arrays.toString(a3));

        int[] a4 = new int[]{1, 3, 2};
        nextPermutation(a4);
        assert !Objects.deepEquals(a4, new int[]{2, 1, 3});
        System.out.println(Arrays.toString(a4));
    }
}

32. Longest Valid Parentheses

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

Example 1:

Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"

Example 2:

Input: “)()())”
Output: 4
Explanation: The longest valid parentheses substring is "()()"
1
Unresolved directive in 0032-longest-valid-parentheses.adoc - include::/home/runner/work/leetcode/leetcode/src/main/java/com/diguage/algorithm/leetcode/_0032_LongestValidParentheses.java[]

33. Search in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Your algorithm’s runtime complexity must be in the order of O(log n).

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.diguage.algorithm.leetcode;

/**
 * = 33. Search in Rotated Sorted Array
 *
 * https://leetcode.com/problems/search-in-rotated-sorted-array/description/[Search in Rotated Sorted Array - LeetCode]
 *
 * Suppose an array sorted in ascending order is rotated at some pivot unknown
 * to you beforehand.
 *
 * (i.e., `[0,1,2,4,5,6,7]` might become `[4,5,6,7,0,1,2]`).
 *
 * You are given a target value to search. If found in the array return its
 * index, otherwise return `-1`.
 *
 * You may assume no duplicate exists in the array.
 *
 * Your algorithm's runtime complexity must be in the order of O(log n).
 *
 * .Example 1:
 * [source]
 * ----
 * Input: nums = [4,5,6,7,0,1,2], target = 0
 * Output: 4
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: nums = [4,5,6,7,0,1,2], target = 3
 * Output: -1
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-09-16 17:45
 */
public class _0033_SearchInRotatedSortedArray {
    public static int search(int[] nums, int target) {
        int result = -1;
        if (null == nums || nums.length == 0) {
            return result;
        }
        int firstNum = nums[0];
        int lastNum = nums[nums.length - 1];
        int separator = -1;
        if (firstNum > lastNum) {
            int head = 0;
            int tail = nums.length - 1;
            while (head <= tail) {
                int mid = head + (tail - head) / 2;
                int midNum = nums[mid];
                if (midNum > nums[mid + 1]) {
                    separator = mid;
                    break;
                }
                if (midNum >= firstNum) {
                    head = mid + 1;
                }
                if (midNum < lastNum) {
                    tail = mid - 1;
                }
            }
        }
        if (separator == -1) {
            return binarySearch(nums, target, 0, nums.length - 1);
        } else {
            if (firstNum <= target && target <= nums[separator]) {
                return binarySearch(nums, target, 0, separator);
            } else {
                return binarySearch(nums, target, separator + 1, nums.length - 1);
            }
        }
    }

    private static int binarySearch(int[] nums, int target, int headIndex, int tailIndex) {
        int head = headIndex;
        int tail = tailIndex;
        while (head <= tail) {
            int mid = head + (tail - head) / 2;
            int midNum = nums[mid];
            if (midNum == target) {
                return mid;
            }
            if (target <= midNum) {
                tail = mid - 1;
            }
            if (midNum < target) {
                head = mid + 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
//        int[] nums = new int[]{4, 5, 6, 7, 0, 1, 2};
//        int target = 0;

//        int[] nums = new int[]{4, 5, 6, 7, 0, 1, 2};
//        int target = 3;

//        int[] nums = new int[]{1};
//        int target = 1;

//        int[] nums = new int[]{1};
//        int target = 0;

//        int[] nums = new int[]{1, 3};
//        int target = 0;

//        int[] nums = new int[]{3, 1};
//        int target = 1;

        int[] nums = new int[]{4, 5, 1, 2, 3};
        int target = 1;
        System.out.println(search(nums, target));
    }
}

34. Find First and Last Position of Element in Sorted Array

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm’s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.diguage.algorithm.leetcode;

import java.util.Arrays;

/**
 * == 34. Find First and Last Position of Element in Sorted Array
 *
 * https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/description/[Find First and Last Position of Element in Sorted Array - LeetCode]
 *
 * Given an array of integers `nums` sorted in ascending order, find the
 * starting and ending position of a given `target` value.
 *
 * Your algorithm's runtime complexity must be in the order of O(log n).
 *
 * If the target is not found in the array, return `[-1, -1]`.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: nums = [5,7,7,8,8,10], target = 8
 * Output: [3,4]
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: nums = [5,7,7,8,8,10], target = 6
 * Output: [-1,-1]
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-09-16 20:50
 */
public class _0034_FindFirstAndLastPositionOfElementInSortedArray {
    public static int[] searchRange(int[] nums, int target) {
        int[] result = new int[]{-1, -1};
        if (null == nums || nums.length == 0) {
            return result;
        }
        int low = 0;
        int high = nums.length - 1;
        int index = -1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int midNum = nums[mid];
            if (midNum == target) {
                index = mid;
                break;
            }
            if (target <= midNum) {
                high = mid - 1;
            }
            if (midNum < target) {
                low = mid + 1;
            }
        }
        if (index < 0) {
            return result;
        }
        int startIndex = index;
        while (startIndex >= 0 && nums[startIndex] == target) {
            startIndex--;
        }
        result[0] = startIndex + 1;

        int endIndex = index;
        while (endIndex < nums.length && nums[endIndex] == target) {
            endIndex++;
        }
        result[1] = endIndex - 1;
        return result;
    }

    public static void main(String[] args) {
//        int[] nums = new int[]{5, 7, 7, 8, 8, 10};
//        int target = 8;

        int[] nums = new int[]{1};
        int target = 1;

        System.out.println(Arrays.toString(searchRange(nums, target)));
    }
}

35. Search Insert Position

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Example 1:

Input: [1,3,5,6], 5
Output: 2

Example 2:

Input: [1,3,5,6], 2
Output: 1

Example 3:

Input: [1,3,5,6], 7
Output: 4

Example 4:

Input: [1,3,5,6], 0
Output: 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.diguage.algorithm.leetcode;

/**
 * = 35. Search Insert Position
 *
 * https://leetcode.com/problems/search-insert-position/description/[Search Insert Position - LeetCode]
 *
 * Given a sorted array and a target value, return the index if the target is
 * found. If not, return the index where it would be if it were inserted in order.
 *
 * You may assume no duplicates in the array.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: [1,3,5,6], 5
 * Output: 2
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: [1,3,5,6], 2
 * Output: 1
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: [1,3,5,6], 7
 * Output: 4
 * ----
 *
 * .Example 4:
 * [source]
 * ----
 * Input: [1,3,5,6], 0
 * Output: 0
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-09-16 21:32
 */
public class _0035_SearchInsertPosition {
    public static int searchInsert(int[] nums, int target) {
        if (null == nums || nums.length == 0) {
            return 0;
        }

        if (target <= nums[0]) {
            return 0;
        }

        if (target > nums[nums.length - 1]) {
            return nums.length;
        }

        int result = -1;
        int low = 0;
        int high = nums.length - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int midNum = nums[mid];
            if (midNum >= target
                && ((mid - 1) >= 0) && nums[mid - 1] < target) {
                result = mid;
                break;
            }
            if ((mid - 1 >= 0) && target <= nums[mid - 1]) {
                high = mid - 1;
            }
            if (midNum < target) {
                low = mid + 1;
            }
        }

        return result;
    }

    public static void main(String[] args) {
        int[] nums = new int[]{1, 3, 5, 6};
        int target = 5;
        System.out.println(searchInsert(nums, target));
    }
}

36. Valid Sudoku

0036 valid sudoku

Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:

  • Each row must contain the digits 1-9 without repetition.

  • Each column must contain the digits 1-9 without repetition.

  • Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.

250px Sudoku by L2G 20050714.svg

A partially filled sudoku which is valid.

The Sudoku board could be partially filled, where empty cells are filled with the character '.'.

Example 1:

Input:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
Output: true

Example 2:

Input:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being
    modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.

Note:

  • A Sudoku board (partially filled) could be valid but is not necessarily solvable.

  • Only the filled cells need to be validated according to the mentioned rules.

  • The given board contain only digits 1-9 and the character '.'.

  • The given board size is always 9x9.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.diguage.algorithm.leetcode;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * = 36. Valid Sudoku
 *
 * https://leetcode.com/problems/valid-sudoku/[Valid Sudoku - LeetCode]
 *
 * Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated *according to the following rules:*
 *
 * . Each row must contain the digits `1-9` without repetition.
 * . Each column must contain the digits `1-9` without repetition.
 * . Each of the 9 3x3 sub-boxes of the grid must contain the digits `1-9` without repetition.
 *
 * The Sudoku board could be partially filled, where empty cells are filled with the character `'.'`.
 *
 * ----
 *
 * .Example 1:
 * [source]
 * ----
 * Input:
 * [
 *   ["5","3",".",".","7",".",".",".","."],
 *   ["6",".",".","1","9","5",".",".","."],
 *   [".","9","8",".",".",".",".","6","."],
 *   ["8",".",".",".","6",".",".",".","3"],
 *   ["4",".",".","8",".","3",".",".","1"],
 *   ["7",".",".",".","2",".",".",".","6"],
 *   [".","6",".",".",".",".","2","8","."],
 *   [".",".",".","4","1","9",".",".","5"],
 *   [".",".",".",".","8",".",".","7","9"]
 * ]
 * Output: true
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input:
 * [
 *   ["8","3",".",".","7",".",".",".","."],
 *   ["6",".",".","1","9","5",".",".","."],
 *   [".","9","8",".",".",".",".","6","."],
 *   ["8",".",".",".","6",".",".",".","3"],
 *   ["4",".",".","8",".","3",".",".","1"],
 *   ["7",".",".",".","2",".",".",".","6"],
 *   [".","6",".",".",".",".","2","8","."],
 *   [".",".",".","4","1","9",".",".","5"],
 *   [".",".",".",".","8",".",".","7","9"]
 * ]
 * Output: false
 * Explanation: Same as Example 1, except with the 5 in the top left corner being
 *     modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
 * ----
 *
 * *Note:*
 *
 * * A Sudoku board (partially filled) could be valid but is not necessarily solvable.
 * * Only the filled cells need to be validated according to the mentioned rules.
 * * The given board contain only digits `1-9` and the character `'.'`.
 * * The given board size is always 9x9.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-06 12:24
 */
public class _0036_ValidSudoku {
    /**
     * Runtime: 5 ms, faster than 21.21% of Java online submissions for Valid Sudoku.
     *
     * Memory Usage: 43.2 MB, less than 95.65% of Java online submissions for Valid Sudoku.
     *
     * Copy from: https://leetcode.com/problems/valid-sudoku/discuss/15472/Short%2BSimple-Java-using-Strings[Short+Simple Java using Strings - LeetCode Discuss]
     */
    public boolean isValidSudoku(char[][] board) {
        Set<String> numbers = new HashSet<>(board.length * board.length);
        for (int y = 0; y < board.length; y++) {
            for (int x = 0; x < board[y].length; x++) {
                if (!Objects.equals(board[y][x], '.')) {
                    String value = "(" + board[y][x] + ")";
                    if (!numbers.add(y + value)
                            || !numbers.add(value + x)
                            || !numbers.add(y / 3 + value + x / 3)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public static void main(String[] args) {
        _0036_ValidSudoku solution = new _0036_ValidSudoku();
        char[][] b1 = {
                {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
                {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
                {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
                {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
                {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
                {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
                {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
                {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
                {'.', '.', '.', '.', '8', '.', '.', '7', '9'}
        };
        boolean r1 = solution.isValidSudoku(b1);
        System.out.println(r1);

        char[][] b2 = {
                {'8', '3', '.', '.', '7', '.', '.', '.', '.'},
                {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
                {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
                {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
                {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
                {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
                {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
                {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
                {'.', '.', '.', '.', '8', '.', '.', '7', '9'}
        };
        boolean r2 = solution.isValidSudoku(b2);
        System.out.println(!r2);
    }
}

37. Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

  • Each of the digits 1-9 must occur exactly once in each row.

  • Each of the digits 1-9 must occur exactly once in each column.

  • Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character '.'.

0037 1

A sudoku puzzle…​

0037 2

…​and its solution numbers marked in red.

Note:

  • The given board contain only digits 1-9 and the character '.'.

  • You may assume that the given Sudoku puzzle will have a single unique solution.

  • The given board size is always 9x9.

解题分析

这道题特别需要关注的点是:只要找到一个解就可以了,不需要求全部解。所以,需要重点思考的是,如何在找到第一个解时,就立即停止搜索。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.diguage.algorithm.leetcode;

import com.diguage.algorithm.util.PrintUtils;

/**
 * = 37. Sudoku Solver
 *
 * https://leetcode.com/problems/sudoku-solver/[(5) Sudoku Solver - LeetCode]
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-03-25 09:34
 */
public class _0037_SudokuSolver {
    public void solveSudoku(char[][] board) {
        backtrack(board, 0);
    }

    /**
     * Runtime: 17 ms, faster than 35.23% of Java online submissions for Sudoku Solver.
     * Memory Usage: 37 MB, less than 21.05% of Java online submissions for Sudoku Solver.
     */
    private boolean backtrack(char[][] board, int step) {
        int len = board.length;
        if (step == len * len) {
            return true;
        }
        int y = step / len;
        int x = step % len;

        for (int i = y; i < len; i++) {
            for (int j = x; j < len; j++) {
                if (board[i][j] != '.') {
                    return backtrack(board, step + 1);
                }
                for (char c = '1'; c <= '9'; c++) {
                    if (!isValid(board, i, j, c)) {
                        continue;
                    }
                    board[i][j] = c;
                    System.out.printf("y=%d,x=%d, num=%s, step=%d %n",
                            y, x, c, step);
                    PrintUtils.printMatrix(board);
                    if (backtrack(board, step + 1)) {
                        return true;
                    }
                    board[i][j] = '.';
                }
                return false;
            }
        }
        return false;
    }

    private boolean isValid(char[][] board, int y, int x, char c) {
        for (int i = 0; i < 9; i++) {
            if (board[(y / 3) * 3 + i / 3][(x / 3) * 3 + i % 3] == c
                    || board[y][i] == c
                    || board[i][x] == c) {
                return false;
            }
        }
        return true;
    }

    /**
     * Copy From
     */
    private boolean backtrackXY(char[][] board, int y, int x) {
        int len = board.length;
        if (x == len) {
            return backtrackXY(board, y + 1, 0);
        }
        if (y == len) {
            return true;
        }
        for (int i = y; i < len; i++) {
            for (int j = x; j < len; j++) {
                if (board[i][j] != '.') {
                    return backtrackXY(board, i, j + 1);
                }
                for (char c = '1'; c <= '9'; c++) {
                    if (!isValid(board, i, j, c)) {
                        continue;
                    }
                    board[i][j] = c;
                    System.out.printf("y=%d,x=%d, num=%s %n", i, j, c);
                    PrintUtils.printMatrix(board);
                    if (backtrackXY(board, i, j + 1)) {
                        return true;
                    }
                    board[i][j] = '.';
                }
                return false;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        char[][] b1 = {
                {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
                {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
                {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
                {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
                {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
                {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
                {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
                {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
                {'.', '.', '.', '.', '8', '.', '.', '7', '9'}
        };
        _0037_SudokuSolver solution = new _0037_SudokuSolver();
        PrintUtils.printMatrix(b1);
        solution.solveSudoku(b1);
        PrintUtils.printMatrix(b1);
    }
}

38. Count and Say

看懂了这道题,相声就已经入门了……

Matrix67 的解释 Conway常数是怎么得来的? | Matrix67: The Aha Moments 还是非常浅显易懂的!

The count-and-say sequence is the sequence of integers with the first five terms as following:

1.     1
2.     11
3.     21
4.     1211
5.     111221

1 is read off as "one 1" or 11.

11 is read off as "two 1s" or 21.

21 is read off as "one 2, then one 1" or 1211.

Given an integer n where 1 ≤ n ≤ 30, generate the nth term of the count-and-say sequence. You can do so recursively, in other words from the previous member read off the digits, counting the number of digits in groups of the same digit.

Note: Each term of the sequence of integers will be represented as a string.

Example 1:

Input: 1
Output: "1"
Explanation: This is the base case.

Example 2:

Input: 4
Output: "1211"
Explanation: For n = 3 the term was "21" in which we have two groups "2" and "1", "2" can be read as "12" which means frequency = 1 and value = 2, the same way "1" is read as "11", so the answer is the concatenation of "12" and "11" which is "1211".
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 38. Count and Say
 *
 * The count-and-say sequence is the sequence of integers with the first five terms as following:
 *
 * ----
 * 1.     1
 * 2.     11
 * 3.     21
 * 4.     1211
 * 5.     111221
 * ----
 *
 * `1` is read off as "`one 1`" or `11`.+
 * `11` is read off as "`two 1s`" or `21`.+
 * `21` is read off as "`one 2`, then `one 1`" or `1211`.+
 *
 * Given an integer n where 1 ≤ n ≤ 30, generate the nth term of the count-and-say sequence. You can do so recursively, in other words from the previous member read off the digits, counting the number of digits in groups of the same digit.
 *
 * Note: Each term of the sequence of integers will be represented as a string.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: 1
 * Output: "1"
 * Explanation: This is the base case.
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: 4
 * Output: "1211"
 * Explanation: For n = 3 the term was "21" in which we have two groups "2" and "1", "2" can be read as "12" which means frequency = 1 and value = 2, the same way "1" is read as "11", so the answer is the concatenation of "12" and "11" which is "1211".
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-17 23:16
 */
public class _0038_CountAndSay {
    /**
     * Runtime: 3 ms, faster than 40.24% of Java online submissions for Count and Say.
     *
     * Memory Usage: 40.9 MB, less than 5.26% of Java online submissions for Count and Say.
     */
    public String countAndSay(int n) {
        String result = "1";
        if (n == 1) {
            return result;
        }
        StringBuilder builder;
        for (int i = 1; i < n; i++) {
            builder = new StringBuilder();
            char[] chars = result.toCharArray();
            Character prefix = null;
            int count = 0;
            for (int j = 0; j < chars.length; j++) {
                char current = chars[j];
                if (Objects.isNull(prefix)) {
                    prefix = current;
                    ++count;
                } else {
                    if (Objects.equals(prefix, current)) {
                        ++count;
                    } else {
                        builder.append(count).append(prefix);
                        prefix = current;
                        count = 1;
                    }
                }
                if (j == chars.length - 1) {
                    builder.append(count).append(prefix);
                }
            }
            result = builder.toString();
        }

        return result;
    }

    public static void main(String[] args) {
        _0038_CountAndSay solution = new _0038_CountAndSay();
        String r1 = solution.countAndSay(5);
        System.out.println(r1.equals("111221") + " : " + r1);
    }
}

39. Combination Sum

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.

  • The solution set must not contain duplicate combinations.

Example 1:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
  [7],
  [2,2,3]
]
Example 2:
Input: candidates = [2,3,5], target = 8,
A solution set is:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

参考 46. Permutations 认真学习一下回溯思想。

0039 1
0039 2
0039 3

思考题:如何做剪枝?这道题通过做剪枝从 164ms 优化到了 9ms。

参考资料

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.

  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [2,3,6,7], `target = `7,
A solution set is:
[
  [7],
  [2,2,3]
]

Example 2:

Input: candidates = [2,3,5]`, `target = 8,
A solution set is:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package com.diguage.algorithm.leetcode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * = 39. Combination Sum
 * <p>
 * https://leetcode.com/problems/combination-sum/description/[Combination Sum - LeetCode]
 * <p>
 * Given a set of candidate numbers (candidates) (without duplicates) and a
 * target number (target), find all unique combinations in candidates where
 * the candidate numbers sums to target.
 * <p>
 * The same repeated number may be chosen from candidates unlimited number of times.
 * <p>
 * *Note:*
 * <p>
 * * All numbers (including target) will be positive integers.
 * * The solution set must not contain duplicate combinations.
 * <p>
 * .Example 1:
 * [source]
 * ----
 * Input: candidates = [2,3,6,7], target = 7,
 * A solution set is:
 * [
 * [7],
 * [2,2,3]
 * ]
 * ----
 * <p>
 * .Example 2:
 * [source]
 * ----
 * Input: candidates = [2,3,5], target = 8,
 * A solution set is:
 * [
 * [2,2,2,2],
 * [2,3,3],
 * [3,5]
 * ]
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2018-09-16 21:56
 */
public class _0039_CombinationSum {
    /**
     * Runtime: 164 ms, faster than 5.05% of Java online submissions for Combination Sum.
     * Memory Usage: 45.5 MB, less than 5.19% of Java online submissions for Combination Sum.
     * <p>
     * ↓
     * <p>
     * Runtime: 9 ms, faster than 17.31% of Java online submissions for Combination Sum.
     * Memory Usage: 41 MB, less than 5.19% of Java online submissions for Combination Sum.
     */
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        if (null == candidates || candidates.length == 0) {
            return Collections.emptyList();
        }
        Arrays.sort(candidates);

        List<List<Integer>> result = new ArrayList<>();
        backtrack(candidates, target, result, new ArrayList<>());
        return result;
    }

    private void backtrack(int[] candidates, int target, List<List<Integer>> result, List<Integer> current) {
        if (target == 0) {
            result.add(new ArrayList<>(current));
        }
        if (target < 0) {
            return;
        }
        for (int candidate : candidates) {
            if (!current.isEmpty() && current.get(current.size() - 1) > candidate) {
                continue;
            }
            current.add(candidate);
            backtrack(candidates, target - candidate, result, current);
            current.remove(current.size() - 1);
        }
    }

    public static void main(String[] args) {
        _0039_CombinationSum solution = new _0039_CombinationSum();
        System.out.println(solution.combinationSum(new int[]{2, 3, 6, 7}, 7));
        System.out.println(solution.combinationSum(new int[]{2, 3, 5}, 8));
    }
}

40. Combination Sum II

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

Each number in candidates may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.

  • The solution set must not contain duplicate combinations.

Example 1:
Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]
Example 2:
Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
  [1,2,2],
  [5]
]
0040 1
0040 2
0040 3

这道题的关键是由于候选值不能重复使用,所以需要向下传递起始位置。可以对比一下 [] 的处理上的不同之处。

思考一下解决重复值时是怎么剪枝的?

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

Each number in candidates may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.

  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

Example 2:

Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
  [1,2,2],
  [5]
]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.diguage.algorithm.leetcode;

import java.util.*;

/**
 * = 40. Combination Sum II
 *
 * https://leetcode.com/problems/combination-sum-ii/[Combination Sum II - LeetCode]
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-27 19:20
 */
public class _0040_CombinationSumII {
    /**
     * Runtime: 2 ms, faster than 100.00% of Java online submissions for Combination Sum II.
     * Memory Usage: 39.5 MB, less than 54.74% of Java online submissions for Combination Sum II.
     */
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        if (Objects.isNull(candidates) || candidates.length == 0) {
            return Collections.emptyList();
        }
        Arrays.sort(candidates);
        List<List<Integer>> result = new ArrayList<>();
        backtrack(candidates, 0, target, result, new ArrayDeque<>());
        return new ArrayList<>(result);
    }

    private void backtrack(int[] candidates, int beginIndex, int target,
                           List<List<Integer>> result, Deque<Integer> current) {
        if (target == 0) {
            result.add(new ArrayList<>(current));
            return;
        }
        for (int i = beginIndex; i < candidates.length; i++) {
            int candidate = candidates[i];
            if (target < candidate) {
                break;
            }
            if (!current.isEmpty() && current.peekLast() > candidate) {
                continue;
            }
            if (beginIndex < i && candidate == candidates[i - 1]) {
                continue;
            }
            current.addLast(candidate);
            // 因为元素不可以重复使用,这里递归传递下去的是 i + 1 而不是 i
            backtrack(candidates, i + 1, target - candidate, result, current);
            current.removeLast();
        }
    }

    public static void main(String[] args) {
        _0040_CombinationSumII solution = new _0040_CombinationSumII();
        int[] c3 = {1, 2};
        System.out.println(solution.combinationSum2(c3, 4));

        int[] c1 = {10, 1, 2, 7, 6, 1, 5};
        System.out.println(solution.combinationSum2(c1, 8));

        int[] c2 = {2, 5, 2, 1, 2};
        System.out.println(solution.combinationSum2(c2, 5));
    }
}

41. First Missing Positive

这道题跟 268. Missing Number - LeetCode 很像!

Given an unsorted integer array, find the smallest missing positive integer.

Example 1:

Input: [1,2,0]
Output: 3

Example 2:

Input: [3,4,-1,1]
Output: 2

Example 3:

Input: [7,8,9,11,12]
Output: 1

Note:

Your algorithm should run in O(n) time and uses constant extra space.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 41. First Missing Positive
 *
 * https://leetcode.com/problems/first-missing-positive/[First Missing Positive - LeetCode]
 *
 * Given an unsorted integer array, find the smallest missing positive integer.
 *
 * .Example 1:
 * [source]
 * ----
 * Input: [1,2,0]
 * Output: 3
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: [3,4,-1,1]
 * Output: 2
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: [7,8,9,11,12]
 * Output: 1
 * ----
 *
 * *Note:*
 *
 * Your algorithm should run in O(n) time and uses constant extra space.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-10-23 12:54:29
 */
public class _0041_FirstMissingPositive {
    /**
     * Runtime: 0 ms, faster than 100.00% of Java online submissions for First Missing Positive.
     *
     * Memory Usage: 34.6 MB, less than 100.00% of Java online submissions for First Missing Positive.
     */
    public int firstMissingPositive(int[] nums) {
        if (Objects.isNull(nums) || nums.length == 0) {
            return 1;
        }
        int length = nums.length;
        for (int i = 0; i < length; ) {
            int iNum = nums[i];
            if (0 < iNum && iNum <= length && nums[iNum - 1] != iNum) {
                swap(nums, i, iNum - 1);
            } else {
                i++;
            }
        }
        int i = 0;
        while (i < length && nums[i] == i + 1) {
            i++;
        }

        return i + 1;
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    public static void main(String[] args) {
        _0041_FirstMissingPositive solution = new _0041_FirstMissingPositive();
        int i1 = solution.firstMissingPositive(new int[]{1, 2, 0});
        System.out.println((i1 == 3) + ", " + i1);

        int i2 = solution.firstMissingPositive(new int[]{3, 4, -1, 1});
        System.out.println((i2 == 2) + ", " + i2);

        int i3 = solution.firstMissingPositive(new int[]{7, 8, 9, 11, 12});
        System.out.println((i3 == 1) + ", " + i3);
    }
}

42. Trapping Rain Water

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

rainwatertrap

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

Example:

Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

解题分析

有点懵逼,没看太明白。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.diguage.algorithm.leetcode;

/**
 * = 42. Trapping Rain Water
 *
 * https://leetcode.com/problems/trapping-rain-water/[Trapping Rain Water - LeetCode]
 *
 * Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
 *
 * image::https://assets.leetcode.com/uploads/2018/10/22/rainwatertrap.png[title="The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!"]
 *
 * .Example:
 * [source]
 * ----
 * Input: [0,1,0,2,1,0,1,3,2,1,2,1]
 * Output: 6
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-07-26 08:49
 */
public class _0042_TrappingRainWater {
    /**
     * Runtime: 0 ms, faster than 100.00% of Java online submissions for Trapping Rain Water.
     * Memory Usage: 38.3 MB, less than 91.10% of Java online submissions for Trapping Rain Water.
     *
     * Copy from: https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/[详细通俗的思路分析,多解法 - 接雨水 - 力扣(LeetCode)]
     */
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int result = 0;
        int leftMax = 0, rightMax = 0;
        while (left < right) {
            if (height[left] < height[right]) {
                if (height[left] >= leftMax) {
                    leftMax = height[left];
                } else {
                    result += (leftMax - height[left]);
                }
                ++left;
            } else {
                if (height[right] > rightMax) {
                    rightMax = height[right];
                } else {
                    result += (rightMax - height[right]);
                }
                --right;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        _0042_TrappingRainWater solution = new _0042_TrappingRainWater();
        int r1 = solution.trap(new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1});
        System.out.println((r1 == 6) + " : " + r1);
    }
}

思考题

尝试一下动态规划解法!

43. Multiply Strings

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.

Example 1:
Input: num1 = "2", num2 = "3"
Output: "6"
Example 2:
Input: num1 = "123", num2 = "456"
Output: "56088"

Note:

  1. The length of both num1 and num2 is < 110.

  2. Both num1 and num2 contain only digits 0-9.

  3. Both num1 and num2 do not contain any leading zero, except the number 0 itself.

  4. You must not use any built-in BigInteger library or convert the inputs to integer directly.

解题思路

0043 1

将每次相乘的计算结果存入到一个数组中,每个元素保存一个位上的数字。

参考资料

  1. 优化版竖式(打败99.4%) - 字符串相乘 - 力扣(LeetCode) — 第二种解法,最初没看明白,但是受他们的启发,我自己想到了。

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.

Example 1:

Input: num1 = "2", num2 = "3"
Output: "6"

Example 2:

Input: num1 = "123", num2 = "456"
Output: "56088"

Note:

  1. The length of both num1 and num2 is < 110.

  2. Both num1 and num2 contain only digits 0-9.

  3. Both num1 and num2 do not contain any leading zero, except the number 0 itself.

  4. You must not use any built-in BigInteger library or convert the inputs to integer directly.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.diguage.algorithm.leetcode;

/**
 * = 43. Multiply Strings
 *
 * https://leetcode.com/problems/multiply-strings/[Multiply Strings - LeetCode]
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-02-03 21:07
 */
public class _0043_MultiplyStrings {
    /**
     * Runtime: 5 ms, faster than 59.85% of Java online submissions for Multiply Strings.
     * Memory Usage: 38.5 MB, less than 16.67% of Java online submissions for Multiply Strings.
     */
    public String multiply(String num1, String num2) {
        if ("0".equals(num1) || "0".equals(num2)) {
            return "0";
        }
        int[] products = new int[num1.length() + num2.length()];
        for (int i = num1.length() - 1; i >= 0; i--) {
            int iNum = num1.charAt(i) - '0';
            if (iNum == 0) {
                continue;
            }
            for (int j = num2.length() - 1; j >= 0; j--) {
                int jNum = num2.charAt(j) - '0';
                int sum = products[i + j + 1] + iNum * jNum;
                products[i + j + 1] = sum % 10;
                products[i + j] += sum / 10;
            }
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < products.length; i++) {
            if (i == 0 && products[i] == 0) {
                continue;
            }
            sb.append(products[i]);
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        _0043_MultiplyStrings solution = new _0043_MultiplyStrings();
        String r5 = solution.multiply("7067", "7967");
        System.out.println("56302789".equals(r5) + " : " + r5);

        String r4 = solution.multiply("6", "501");
        System.out.println("3006".equals(r4) + " : " + r4);

        String r1 = solution.multiply("123", "456");
        System.out.println("56088".equals(r1) + " : " + r1);

        String r2 = solution.multiply("123", "4567");
        System.out.println("561741".equals(r2) + " : " + r2);

        String r3 = solution.multiply("88888888", "999999999");
        System.out.println("88888887911111112".equals(r3) + " : " + r3);
    }
}

44. Wildcard Matching

Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

Note:

  • s could be empty and contains only lowercase letters a-z.

  • p could be empty and contains only lowercase letters a-z, and characters like <font face="monospace">? or *.

Example 1:

Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".

Example 2:

Input:
s = "aa"
p = ""
*Output: true
Explanation: '*' matches any sequence.

Example 3:

Input:
s = "cb"
p = "?a"
Output: false
Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.

Example 4:

Input:
s = "adceb"
p = "a*b"
*Output: true
Explanation: The first '' matches the empty sequence, while the second '' matches the substring "dce".

Example 5:

Input:
s = "acdcb"
p = "a*c?b"
Output: false
1
Unresolved directive in 0044-wildcard-matching.adoc - include::/home/runner/work/leetcode/leetcode/src/main/java/com/diguage/algorithm/leetcode/_0044_WildcardMatching.java[]

45. Jump Game II

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Your goal is to reach the last index in the minimum number of jumps.

Example:

Input: [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
    Jump 1 step from index 0 to 1, then 3 steps to the last index.

Note:

You can assume that you can always reach the last index.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.diguage.algorithm.leetcode;

import java.util.Objects;

/**
 * = 45. Jump Game II
 *
 * https://leetcode.com/problems/jump-game-ii/[Jump Game II - LeetCode]
 *
 * Given an array of non-negative integers, you are initially positioned at the first index of the array.
 *
 * Each element in the array represents your maximum jump length at that position.
 *
 * Your goal is to reach the last index in the minimum number of jumps.
 *
 * .Example:
 * [source]
 * ----
 * Input: [2,3,1,1,4]
 * Output: 2
 * Explanation: The minimum number of jumps to reach the last index is 2.
 * Jump 1 step from index 0 to 1, then 3 steps to the last index.
 * ----
 *
 * *Note:*
 *
 * You can assume that you can always reach the last index.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-10-26 11:29
 */
public class _0045_JumpGameII {
    /**
     * Runtime: 1 ms, faster than 99.98% of Java online submissions for Jump Game II.
     *
     * Memory Usage: 36.4 MB, less than 100.00% of Java online submissions for Jump Game II.
     */
    public int jump(int[] nums) {
        if (Objects.isNull(nums) || nums.length == 0) {
            return 0;
        }
        int step = 0;
        int currentStepEnd = 0;
        int currentFarthestIndex = 0;
        for (int i = 0; i < nums.length - 1; i++) {
            currentFarthestIndex = Math.max(currentFarthestIndex, i + nums[i]);
            if (i == currentStepEnd) {
                step++;
                currentStepEnd = currentFarthestIndex;
            }
        }
        return step;
    }

    // TODO: Dynamic Programming

    public static void main(String[] args) {
        _0045_JumpGameII solution = new _0045_JumpGameII();
        int r1 = solution.jump(new int[]{2, 3, 1, 1, 4});
        System.out.println((r1 == 2) + " : " + r1);
    }
}

46. Permutations

首先介绍“回溯”算法的应用。“回溯”算法也叫“回溯搜索”算法,主要用于在一个庞大的空间里搜索我们所需要的问题的解。我们每天使用的“搜索引擎”就是帮助我们在庞大的互联网上搜索我们需要的信息。“搜索”引擎的“搜索”和“回溯搜索”算法的“搜索”意思是一样的。

“回溯”指的是“状态重置”,可以理解为“回到过去”、“恢复现场”,是在编码的过程中,是为了节约空间而使用的一种技巧。而回溯其实是“深度优先遍历”特有的一种现象。之所以是“深度优先遍历”,是因为我们要解决的问题通常是在一棵树上完成的,在这棵树上搜索需要的答案,一般使用深度优先遍历。

“全排列”就是一个非常经典的“回溯”算法的应用。我们知道,N 个数字的全排列一共有 N! 这么多个。

使用编程的方法得到全排列,就是在这样的一个树形结构中进行编程,具体来说,就是执行一次深度优先遍历,从树的根结点到叶子结点形成的路径就是一个全排列。

0046 1

说明:

  1. 每一个结点表示了“全排列”问题求解的不同阶段,这些阶段通过变量的“不同的值”体现;

  2. 这些变量的不同的值,也称之为“状态”;

  3. 使用深度优先遍历有“回头”的过程,在“回头”以后,状态变量需要设置成为和先前一样;

  4. 因此在回到上一层结点的过程中,需要撤销上一次选择,这个操作也称之为“状态重置”;

  5. 深度优先遍历,可以直接借助系统栈空间,为我们保存所需要的状态变量,在编码中只需要注意遍历到相应的结点的时候,状态变量的值是正确的,具体的做法是:往下走一层的时候,path 变量在尾部追加,而往回走的时候,需要撤销上一次的选择,也是在尾部操作,因此 path 变量是一个栈。

  6. 深度优先遍历通过“回溯”操作,实现了全局使用一份状态变量的效果。

解决一个回溯问题,实际上就是一个决策树的遍历过程。只需要思考 3 个问题:

  1. 路径:也就是已经做出的选择。

  2. 选择列表:也就是你当前可以做的选择。

  3. 结束条件:也就是到达决策树底层,无法再做选择的条件。

代码方面,回溯算法的框架:

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return

    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」,特别简单。

必须说明的是,不管怎么优化,都符合回溯框架,而且时间复杂度都不可能低于 O(N!),因为穷举整棵决策树是无法避免的。这也是回溯算法的一个特点,不像动态规划存在重叠子问题可以优化,回溯算法就是纯暴力穷举,复杂度一般都很高。

参考资料

Given a collection of distinct integers, return all possible permutations.

Example:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.diguage.algorithm.leetcode;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * = 46. Permutations
 *
 * https://leetcode.com/problems/permutations/[Permutations - LeetCode]
 *
 * Given a collection of *distinct* integers, return all possible permutations.
 *
 * .Example:
 * [source]
 * ----
 * Input: [1,2,3]
 * Output:
 * [
 *   [1,2,3],
 *   [1,3,2],
 *   [2,1,3],
 *   [2,3,1],
 *   [3,1,2],
 *   [3,2,1]
 * ]
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-24 12:35
 */
public class _0046_Permutations {
    /**
     * Runtime: 5 ms, faster than 8.40% of Java online submissions for Permutations.
     *
     * Memory Usage: 45.3 MB, less than 5.68% of Java online submissions for Permutations.
     *
     * Copy from: https://leetcode.com/problems/permutations/discuss/18239/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partioning)[A general approach to backtracking questions in Java (Subsets, Permutations, Combination Sum, Palindrome Partioning) - LeetCode Discuss]
     */
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new LinkedList<>();
        backtrack(nums, result, new ArrayList<Integer>());
        return result;
    }

    private void backtrack(int[] nums, List<List<Integer>> result, ArrayList<Integer> path) {
        if (path.size() == nums.length) {
            result.add(new ArrayList<>(path));
        } else {
            for (int i = 0; i < nums.length; i++) {
                int num = nums[i];
                if (path.contains(num)) {
                    continue;
                }
                path.add(num);
                backtrack(nums, result, path);
                path.remove(path.size() - 1);
            }
        }
    }


    public static void main(String[] args) {
        _0046_Permutations solution = new _0046_Permutations();
        int[] n1 = {1, 2, 3};
        List<List<Integer>> r1 = solution.permute(n1);
        System.out.println(Objects.toString(r1));
    }
}

47. Permutations II

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

Example:
Input: [1,1,2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]
0047 1

思考:去重剪枝的判断是怎么实现的?

参考资料

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

Example:

Input: [1,1,2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.diguage.algorithm.leetcode;

import java.util.*;

/**
 * = 47. Permutations II
 *
 * https://leetcode.com/problems/permutations-ii/[Permutations II - LeetCode]
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-27 20:29
 */
public class _0047_PermutationsII {
    /**
     * Runtime: 1 ms, faster than 100.00% of Java online submissions for Permutations II.
     * Memory Usage: 41.6 MB, less than 11.94% of Java online submissions for Permutations II.
     */
    public List<List<Integer>> permuteUnique(int[] nums) {
        if (Objects.isNull(nums) || nums.length == 0) {
            return Collections.emptyList();
        }
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        List<List<Integer>> result = new ArrayList<>();
        backtrack(nums, 0, used, result, new ArrayDeque<>());
        return result;
    }

    private void backtrack(int[] nums, int startIndex, boolean[] used,
                           List<List<Integer>> result, Deque<Integer> current) {
        if (nums.length == startIndex) {
            result.add(new ArrayList<>(current));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (!used[i]) {

                // 修改 2:在 used[i - 1] 刚刚被撤销的时候剪枝,说明接下来会被选择,搜索一定会重复,故"剪枝"
                if (i > 0 && nums[i - 1] == nums[i] && !used[i - 1]) {
                    continue;
                }

                used[i] = true;
                current.addLast(nums[i]);
                backtrack(nums, startIndex + 1, used, result, current);

                current.removeLast();
                used[i] = false;
            }
        }
    }

    public static void main(String[] args) {
        _0047_PermutationsII solution = new _0047_PermutationsII();
        int[] n1 = {1, 1, 2};
        System.out.println(solution.permuteUnique(n1));
    }
}

48. Rotate Image

You are given an n x n 2D matrix representing an image.

Rotate the image by 90 degrees (clockwise).

Note:

You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.

Example 1:

Given input matrix =
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],

rotate the input matrix in-place such that it becomes:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

Example 2:

Given input matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
],

rotate the input matrix in-place such that it becomes:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package com.diguage.algorithm.leetcode;

import java.util.Objects;

import static com.diguage.algorithm.util.PrintUtils.printMatrix;

/**
 * = 48. Rotate Image
 *
 * https://leetcode.com/problems/rotate-image/[Rotate Image - LeetCode]
 *
 * You are given an n x n 2D matrix representing an image.
 *
 * Rotate the image by 90 degrees (clockwise).
 *
 * *Note:*
 *
 * You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
 *
 * .Example 1:
 * [source]
 * ----
 * Given input matrix =
 * [
 *   [1,2,3],
 *   [4,5,6],
 *   [7,8,9]
 * ],
 *
 * rotate the input matrix in-place such that it becomes:
 * [
 *   [7,4,1],
 *   [8,5,2],
 *   [9,6,3]
 * ]
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Given input matrix =
 * [
 *   [ 5, 1, 9,11],
 *   [ 2, 4, 8,10],
 *   [13, 3, 6, 7],
 *   [15,14,12,16]
 * ],
 *
 * rotate the input matrix in-place such that it becomes:
 * [
 *   [15,13, 2, 5],
 *   [14, 3, 4, 1],
 *   [12, 6, 8, 9],
 *   [16, 7,10,11]
 * ]
 * ----
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2019-10-24 00:57:55
 */
public class _0048_RotateImage {
    /**
     * Runtime: 0 ms, faster than 100.00% of Java online submissions for Rotate Image.
     *
     * Memory Usage: 36.3 MB, less than 100.00% of Java online submissions for Rotate Image.
     */
    public void rotate(int[][] matrix) {
        if (Objects.isNull(matrix) || matrix.length == 0) {
            return;
        }
        int length = matrix.length;
        // 先交换行,这样操作更方便,但是也会有更多的额外空间。
        for (int i = 0; i < length / 2; i++) {
            int[] temp = matrix[i];
            matrix[i] = matrix[length - 1 - i];
            matrix[length - 1 - i] = temp;
        }
//        printMatrix(matrix);
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < i; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
    }

    /**
     * Runtime: 0 ms, faster than 100.00% of Java online submissions for Rotate Image.
     *
     * Memory Usage: 36.2 MB, less than 100.00% of Java online submissions for Rotate Image.
     */
    public void rotate1(int[][] matrix) {
        if (Objects.isNull(matrix) || matrix.length == 0) {
            return;
        }
        int length = matrix.length;
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < i; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        printMatrix(matrix);
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < length / 2; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[i][length - j - 1];
                matrix[i][length - j - 1] = temp;
            }
        }
    }

    public static void main(String[] args) {
        _0048_RotateImage solution = new _0048_RotateImage();
        int[][] array1 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
        printMatrix(array1);
        solution.rotate(array1);
        printMatrix(array1);

        int[][] array2 = {{5, 1, 9, 11}, {2, 4, 8, 10}, {13, 3, 6, 7}, {15, 14, 12, 16}};
        printMatrix(array2);
        solution.rotate(array2);
        printMatrix(array2);
    }
}

49. Group Anagrams

计数字符数量的解法有些精巧!这里想起来了波利亚在《怎样解题》中,着重强调的一点:一点要充分挖掘题目中的一直变量。题目中已经明确给出,所有的字符都是小写字符。但却没有意识到它的重要性!

Given an array of strings, group anagrams together.

Example:

Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

Note:

  • All inputs will be in lowercase.

  • The order of your output does not matter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.diguage.algorithm.leetcode;

import java.util.*;

/**
 * = 49. Group Anagrams
 *
 * https://leetcode.com/problems/group-anagrams/[Group Anagrams - LeetCode]
 *
 * Given an array of strings, group anagrams together.
 *
 * .Example:
 * [source]
 * ----
 * Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
 * Output:
 * [
 *   ["ate","eat","tea"],
 *   ["nat","tan"],
 *   ["bat"]
 * ]
 * ----
 *
 * *Note:*
 *
 * * All inputs will be in lowercase.
 * * The order of your output does not matter.
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-06 21:42
 */
public class _0049_GroupAnagrams {
    /**
     * Runtime: 16 ms, faster than 22.85% of Java online submissions for Group Anagrams.
     *
     * Memory Usage: 40.4 MB, less than 96.49% of Java online submissions for Group Anagrams.
     */
    public List<List<String>> groupAnagrams(String[] strs) {
        if (Objects.isNull(strs) || strs.length == 0) {
            return Collections.emptyList();
        }
        Map<String, List<String>> charsToStringsMap = new HashMap<>();
        int[] count = new int[26];
        for (String str : strs) {
            Arrays.fill(count, 0);
            char[] chars = str.toCharArray();
            for (char aChar : chars) {
                count[aChar - 'a']++;
            }
            StringBuilder builder = new StringBuilder(26 * 2);
            for (int i : count) {
                builder.append("#").append(i);
            }
            String key = builder.toString();
            List<String> strings = charsToStringsMap.getOrDefault(key, new ArrayList<>());
            strings.add(str);
            charsToStringsMap.put(key, strings);
        }
        return new ArrayList<>(charsToStringsMap.values());
    }

    /**
     * Runtime: 8 ms, faster than 96.90% of Java online submissions for Group Anagrams.
     *
     * Memory Usage: 41.1 MB, less than 95.32% of Java online submissions for Group Anagrams.
     */
    public List<List<String>> groupAnagramsSort(String[] strs) {
        if (Objects.isNull(strs) || strs.length == 0) {
            return Collections.emptyList();
        }
        Map<String, List<String>> charsToStringsMap = new HashMap<>();
        for (String str : strs) {
            char[] chars = str.toCharArray();
            Arrays.sort(chars);
            String key = new String(chars);
            List<String> strings = charsToStringsMap.getOrDefault(key, new ArrayList<>());
            strings.add(str);
            charsToStringsMap.put(key, strings);
        }
        return new ArrayList<>(charsToStringsMap.values());
    }

    public static void main(String[] args) {
        _0049_GroupAnagrams solution = new _0049_GroupAnagrams();
        String[] s1 = {"eat", "tea", "tan", "ate", "nat", "bat"};
        List<List<String>> r1 = solution.groupAnagrams(s1);
        System.out.println(Arrays.deepToString(r1.toArray()));
    }
}

50. Pow(x, n)

首先,可以把"一半的计算结果"存储起来,节省一半的递归调用;

其次,没想到还需要处理"无穷"的情况!

另外,思考一下,如果使用迭代来实现?

Implement pow(x, n), which calculates x raised to the power n (xn).

Example 1:

Input: 2.00000, 10
Output: 1024.00000

Example 2:

Input: 2.10000, 3
Output: 9.26100

Example 3:

Input: 2.00000, -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25

Note:

  • -100.0 < x < 100.0

  • n is a 32-bit signed integer, within the range [-231, 2^31 ^- 1]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package com.diguage.algorithm.leetcode;

/**
 * = 50. Pow(x, n)
 *
 * https://leetcode.com/problems/powx-n/[Pow(x, n) - LeetCode]
 *
 * Implement `pow(x, n)`, which calculates x raised to the power n (x^n^).
 *
 * .Example 1:
 * [source]
 * ----
 * Input: 2.00000, 10
 * Output: 1024.00000
 * ----
 *
 * .Example 2:
 * [source]
 * ----
 * Input: 2.10000, 3
 * Output: 9.26100
 * ----
 *
 * .Example 3:
 * [source]
 * ----
 * Input: 2.00000, -2
 * Output: 0.25000
 * Explanation: 2-2 = 1/22 = 1/4 = 0.25
 * ----
 *
 * *Note:*
 *
 * * `-100.0 < x < 100.0`
 * * n is a 32-bit signed integer, within the range [−2^31^, 2^31^ − 1]
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-01-13 21:19
 */
public class _0050_PowXN {

    /**
     * Runtime: 1 ms, faster than 94.10% of Java online submissions for Pow(x, n).
     *
     * Memory Usage: 34.4 MB, less than 5.88% of Java online submissions for Pow(x, n).
     */
    public double myPow(double x, int n) {
        if (n == 0) {
            return 1.0;
        }
        if (n < 0) {
            x = 1 / x;
            n = -n;
        }

        double semiResult = myPow(x, n / 2);
        if (Double.isInfinite(semiResult)) {
            return 0.0;
        }

        return (n % 2 == 0 ? 1.0 : x) * semiResult * semiResult;
    }

    /**
     * Time Limit Exceeded
     * <p>
     * Copy from:
     */
    public double myPowTimeout(double x, int n) {
        if (n == 0) {
            return 1;
        }
        if (n < 0) {
            x = 1 / x;
            n = -n;
        }
        return n % 2 == 0 ? myPowTimeout(x, n / 2) * myPowTimeout(x, n / 2)
                : x * myPowTimeout(x, n / 2) * myPowTimeout(x, n / 2);
    }

    public static void main(String[] args) {
        _0050_PowXN solution = new _0050_PowXN();
        double r1 = solution.myPow(2.0, -2);
        System.out.println(r1);

        double r2 = solution.myPow(2.1, 3);
        System.out.println(r2);

        double r3 = solution.myPow(-2.1, 3);
        System.out.println(r3);

        double r4 = solution.myPow(2, Integer.MIN_VALUE);
        System.out.println(r4);
    }
}

51. N-Queens

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

0051 0 8 queens

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where Q and . both indicate a queen and an empty space respectively.

Example:
Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
 ]

Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.

解题分析

八皇后问题是回溯思想的经典题目。

当在棋盘上放置了一个皇后后,立即排除当前行,列和对应的两个对角线。这里有一点可以优化:我们从上向下进行尝试,所以,只需要判断当前行以上的相关节点是否冲突即可。另外,先检查再渐进点,合适之后,再向前走,可以做到有效地剪枝。

0051 1

这里有个知识点需要注意:

对于所有的主对角线有 行号 + 列号 = 常数
对于所有的次对角线有 行号 - 列号 = 常数
如下图所示:

0051 2

利用回溯解题时,只回溯一半,然后将每个解反转即可求得另外一般解。这里有个细节需要注意:如果长度是奇数,而且第一行中间是合法位置,则在回溯过程中已经产生了对称解法。就不需要再反转了。

参考资料

The n-queens puzzle is the problem of placing n queens on an n×_n_ chessboard such that no two queens attack each other.

8 queens

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

Example:

Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package com.diguage.algorithm.leetcode;

import java.util.ArrayList;
import java.util.List;

import static com.diguage.algorithm.util.PrintUtils.printMatrix;

/**
 * = 51. N-Queens
 *
 * [N-Queens - LeetCode](https://leetcode.com/problems/n-queens/)
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2020-02-05 12:55
 */
public class _0051_NQueens {
    /**
     * Runtime: 4 ms, faster than 64.59% of Java online submissions for N-Queens.
     * Memory Usage: 41.3 MB, less than 5.41% of Java online submissions for N-Queens.
     */
    public List<List<String>> solveNQueens(int n) {
        int[][] matrix = new int[n][n];
        List<List<String>> result = new ArrayList<>();
        backtrack(matrix, 0, 0, result);
        int size = result.size();
        if (size == 0) {
            return result;
        }
        for (int i = 0; i < size; i++) {
            List<String> om = result.get(i);
            // 如果长度是奇数,而且第一行中间是合法位置,则在回溯过程中已经产生了对称解法。
            if (!(n % 2 == 1 && om.get(0).charAt(getMid(n)) == 'Q')) {
                List<String> nm = reverseMatrix(om);
                result.add(nm);
            }
        }
        return result;
    }

    private List<String> reverseMatrix(List<String> matrix) {
        List<String> result = new ArrayList<>(matrix.size());
        for (String s : matrix) {
            StringBuilder sb = new StringBuilder(s);
            result.add(sb.reverse().toString());
        }
        return result;
    }

    private void backtrack(int[][] matrix, int y, int step, List<List<String>> result) {
        int length = matrix.length;
        if (step == length) {
            result.add(matrixToList(matrix));
            return;
        }
        for (