KK's blog

每天积累多一些

0%

LeetCode 056 Merge Intervals

Given a collection of intervals, merge all overlapping intervals.

For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

题目大意:

给定几个区间,要求合并重叠区间,返回结果.

解题思路:

A公司的考题。这条题难点在于判断是否合并,怎么合并,新区间合并多个区间。

  1. 按start排序。
  2. 定义API:如何合并两个区间(两情况),两个区间是否可以合并
  3. 遍历每个区间,产生新区间并将其带入到下一轮循环。这是难点,公式为 新区间=新区间+输入区间[i],这也分为两种情况,可合并和不可合并
    不可合并时,前状态的新区间成为结果,公式为新区间=输入区间[i]。
  4. 若不想特别处理循环边界,可加入空区间到末尾(见Java实现,它把新区间=输入区间[i]放入了下一轮)。若不如此做,可将空区间放入开头。

注意事项:

  1. 先按左节点排序
  2. 区间的右端与另一个区间的左端一样,也算重叠,如[1,2],[2,3]。
  3. 原输入加入首节点的左边界fake区间。避免for循环的特殊处理。2. 最后一个区间的情况。
  4. 合并后生成新区间,要与下一个继续尝试合并。

Python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort(key=lambda x: x[0])
new_interval = [intervals[0][0], intervals[0][0]]
res = []
for interval in intervals:
if self.can_merge(new_interval, interval):
new_interval = self.merge_two_intervals(new_interval, interval)
else:
res.append(new_interval)
new_interval = interval
res.append(new_interval)
return res

def can_merge(self, interval, interval2):
return interval[1] >= interval2[0]

def merge_two_intervals(self, interval, interval2):
return [interval[0], max(interval[1], interval2[1])]

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
public List<Interval> merge(List<Interval> intervals) {
Collections.sort(intervals, new Comparator<Interval>(){
public int compare(Interval v1, Interval v2){
return v1.start - v2.start;
}
});
intervals.add(new Interval(Integer.MAX_VALUE, Integer.MAX_VALUE));
List<Interval> re = new ArrayList<Interval>();
Interval newInterval = null;
for(int i=1;i<intervals.size();i++){
if(newInterval==null)
newInterval = intervals.get(i-1);
if(canMerge(newInterval,intervals.get(i))){
newInterval = mergeIntervals(newInterval,intervals.get(i));
}
else{
re.add(newInterval);
newInterval = null;
}
}
return re;
}


//假设in与in2按start排序,所以只有两情况:
/*
* In -------
* In2 ---
* In2 --------
*/
public boolean canMerge(Interval in, Interval in2){
if(in2.start == Integer.MAX_VALUE)
return false;
return in.end>=in2.start;
}

public Interval mergeIntervals(Interval in, Interval in2){
return new Interval(in.start, Math.max(in.end, in2.end));
}

算法分析:

时间复杂度为O(nlogn),空间复杂度O(1)

LeetCode 1197 Minimum Knight Moves

In an infinite chess board with coordinates from -infinity to +infinity, you have a knight at square [0, 0].

A knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal direction, then one square in an orthogonal direction.

Return the minimum number of steps needed to move the knight to the square [x, y].  It is guaranteed the answer exists.

Example 1:

<pre>Input: x = 2, y = 1 Output: 1 Explanation: [0, 0] → [2, 1] </pre>

Example 2:

<pre>Input: x = 5, y = 5 Output: 4 Explanation: [0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5] </pre>

Constraints:

  • |x| + |y| <= 300

Because x and y are constrained to be in range[-300, 300], we can use BFS to find the minimum steps needed to reach target(x, y). Furthermore, we can only consider the case that x >=0 && y >=0 since the chess board is symmetric.  The bfs implementation is pretty straightforward. There are two important points you need to be careful with.

1.  Pruning. We can limit the search dimension within 310 * 310. Any moves that lead to a position that is outside this box will not yield an optimal result.

2. Initially, you used a Set of type int[] to track visited positions. This caused TLE because you didn't overwrite the hashCode and equals methods for int[]. As a result, Set uses the default hashCode and equals method when checking if an element is already in the set. For equals(), The default implementation provided by the JDK is based on memory location — two objects are equal if and only if they are stored in the same memory address. For a comprehensive reading, refer to https://dzone.com/articles/working-with-hashcode-and-equals-in-java

O(x * y) runtime and space

题目大意:

象棋一样,走日字到达目标点的最小次数。

解题思路:

这题是最短路径题,第一时间想到BFS。

解题步骤:

这题是最短路径题,第一时间想到BFS。这是一条典型的单源最短路径问题。用Distance BFS模板

  1. 建距离map。
  2. BFS访问。

注意事项:

  1. 有边界限制

Python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def minKnightMoves(self, x: int, y: int) -> int:
return self.bfs(0, 0, x, y)

def bfs(self, start_x, start_y, target_x, target_y):
directions = {(2, 1), (1, 2), (-1, 2), (-2, 1), (-2, -1), (-1, -2), (1, -2), (2, -1)}
queue = deque([(start_x, start_y)])
visited = {(start_x, start_y)}
distance = {(start_x, start_y): 0}
while queue:
node = queue.popleft()
if node == (target_x, target_y):
return distance[node]

for direction in directions:
neighbor = (node[0] + direction[0], node[1] + direction[1])
if neighbor in visited:
continue
queue.append(neighbor)
visited.add(neighbor)
distance[neighbor] = distance[node] + 1

注意事项:

  1. 用map记录距离一定要将首节点加入到map中,否则求距离时候会NPE。
  2. visited我一开始实现用HashSet但因为没有实现equals导致LTE,改成矩阵即可。

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
int[] directX = new int[]{1, 1,-1,-1,2,2,-2,-2};
int[] directY = new int[]{2,-2,2,-2,1,-1,1,-1};

public int shortestPath(boolean[][] grid, Point source, Point destination) {
if(grid == null || grid.length == 0 || grid[0].length == 0)
return -1;

Queue<Point> q = new LinkedList<>();
Map<Point, Integer> map = new HashMap<>();
map.put(source, 0); // remember
boolean[][] visited = new boolean[grid.length][grid[0].length];
q.offer(source);
visited[source.x][source.y] = true; // use hashSet is wrong.
while(!q.isEmpty()) {
Point p = q.poll();
if(p.x == destination.x && p.y == destination.y)
return map.get(p);
for(Point neighbor : getNeighbors(p)) {
if(!isValid(grid, neighbor) || visited[neighbor.x][neighbor.y])
continue;
q.offer(neighbor);
visited[neighbor.x][neighbor.y] = true;
map.put(neighbor, map.get(p) + 1);
}
}

return -1;
}

List<Point> getNeighbors(Point point) {
List<Point> result = new ArrayList<>();
for(int i = 0; i < 8; i++) {
result.add(new Point(point.x + directX[i], point.y + directY[i]));
}
return result;
}

boolean isValid(boolean[][] grid, Point point) {
if(point.x >= 0 && point.x < grid.length && point.y >= 0 && point.y < grid[0].length
&& !grid[point.x][point.y])
return true;
else return false;
}

算法分析:

时间复杂度为棋盘大小<code>O(n*m</sup>)</code>,空间复杂度O(n)

LeetCode 133 Clone Graph

Given a reference of a node in a connected undirected graph.

Return a deep copy (clone) of the graph.

Each node in the graph contains a val (int) and a list (List[Node]) of its neighbors.

<pre>class Node { public int val; public List<Node> neighbors; } </pre>

Test case format:

For simplicity sake, each node's value is the same as the node's index (1-indexed). For example, the first node with val = 1, the second node with val = 2, and so on. The graph is represented in the test case using an adjacency list.

Adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.

The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.

Example 1:

<pre>Input: adjList = [[2,4],[1,3],[2,4],[1,3]] Output: [[2,4],[1,3],[2,4],[1,3]] Explanation: There are 4 nodes in the graph. 1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4). 2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3). 3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4). 4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = 3). </pre>

Example 2:

<pre>Input: adjList = [[]] Output: [[]] Explanation: Note that the input contains one empty list. The graph consists of only one node with val = 1 and it does not have any neighbors. </pre>

Example 3:

<pre>Input: adjList = [] Output: [] Explanation: This an empty graph, it does not have any nodes. </pre>

Example 4:

<pre>Input: adjList = [[2],[1]] Output: [[2],[1]] </pre>

Constraints:

  • 1 <= Node.val <= 100
  • Node.val is unique for each node.
  • Number of Nodes will not exceed 100.
  • There is no repeated edges and no self-loops in the graph.
  • The Graph is connected and all nodes can be visited starting from the given node.

</div>

</div>

题目大意:

深度复制图。注意要复制所有邻接节点。

算法I解题思路(推荐):

三步走。分开写逻辑会显得清晰点。

  1. BFS搜索所有节点,变成邻接表节点列表。
  2. 复制节点。旧新节点映射存在dict中
  3. 根据node.neighbors复制边。

注意事项:

  1. 空节点判断Line 2-3
  2. BFS访问是收集节点列表,并不是变成邻接表。如果是含循环的图,由于用了visited,所以邻接表只能复制一半的边,不能用邻接表

Python代码:

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
def cloneGraph(self, node: 'Node') -> 'Node':
if not node:
return None
di = {}
node_list = self.bfs(node)
for n in node_list:
di[n] = Node(n.val)
for n in node_list:
for n2 in n.neighbors:
di[n].neighbors.append(di[n2])
return di[node]

def bfs(self, input):
queue = deque([input])
visited = {input}
# graph = collections.defaultdict(list)
res = []
while queue:
node = queue.popleft()
# graph[node] = []
res.append(node)
for neighbor in node.neighbors:
if neighbor in visited:
continue
queue.append(neighbor)
visited.add(neighbor)
# graph[node].append(neighbor)
return res

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
// another bfs3 method uses 3 steps, convert graph to adjacent list by bfs (flatten the graph), 
//clone vertices, clone edges
public void bfs3(UndirectedGraphNode node, HashMap<UndirectedGraphNode, UndirectedGraphNode> map) {
ArrayList<UndirectedGraphNode> nodes = getNodes(node);

// Copy vertices
for(UndirectedGraphNode old : nodes) {
UndirectedGraphNode newNode = new UndirectedGraphNode(old.label);
map.put(old, newNode);
}

// Copy edges
for(UndirectedGraphNode old : nodes) {
for(UndirectedGraphNode neighbor : old.neighbors) {
map.get(old).neighbors.add(map.get(neighbor));
}
}
}

public ArrayList<UndirectedGraphNode> getNodes(UndirectedGraphNode node) {
Queue<UndirectedGraphNode> q = new LinkedList<>();
Set<UndirectedGraphNode> result = new HashSet<>();
q.offer(node);
result.add(node); // Use result set so we can save the visited set
while(!q.isEmpty()) {
UndirectedGraphNode n = q.poll();
for(UndirectedGraphNode neighbor : n.neighbors) {
if(result.contains(neighbor))
continue;
q.offer(neighbor);
result.add(neighbor);
}
}
ArrayList<UndirectedGraphNode> reList = new ArrayList<UndirectedGraphNode>();
reList.addAll(result);
return reList;
}


算法II解题思路:

不分开三步写

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
public UndirectedGraphNode cloneGraph2(UndirectedGraphNode node) {
if(node == null)
return null;

HashMap<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<>();
bfs(node, map);
return map.get(node);
}

public void bfs(UndirectedGraphNode node, HashMap<UndirectedGraphNode, UndirectedGraphNode> map) {
Queue<UndirectedGraphNode> q = new LinkedList<>();
q.offer(node);
map.put(node, new UndirectedGraphNode(node.label));
while(!q.isEmpty()) {
UndirectedGraphNode head = q.poll();
for(UndirectedGraphNode neighbor : head.neighbors) {
if(!map.containsKey(neighbor)) {
q.offer(neighbor);
// Clone children's vertex
map.put(neighbor, new UndirectedGraphNode(neighbor.label));
}
// Clone edge
map.get(head).neighbors.add(map.get(neighbor));
}
}
}


算法II解题思路:

DFS。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
HashMap<Integer, UndirectedGraphNode> map = new HashMap<Integer, UndirectedGraphNode>();
return cloneGraphR(node, map);
}

public UndirectedGraphNode cloneGraphR(UndirectedGraphNode node,
HashMap<Integer, UndirectedGraphNode> map) {
if (node == null)
return node;
if (map.containsKey(node.label))
return map.get(node.label);

UndirectedGraphNode result = new UndirectedGraphNode(node.label);
map.put(node.label, result);
for (UndirectedGraphNode child : node.neighbors) {
result.neighbors.add(cloneGraphR(child, map));
}
return result;
}

算法分析:

时间复杂度为O(# of results),空间复杂度O(lengh(high))

LeetCode 126 Word Ladder <div>

Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:

  1. Only one letter can be changed at a time
  2. Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

Note:

  • Return an empty list if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume beginWord and endWord are non-empty and are not the same.

Example 1:

<pre>Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]

Output: [ ["hit","hot","dot","dog","cog"],   ["hit","hot","lot","log","cog"] ] </pre>

Example 2:

<pre>Input: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log"]

Output: []

Explanation: The endWord "cog" is not in wordList, therefore no possibletransformation. </pre>

</div>

题目大意:

给定一个字典和两个单词。每次变换一个字母的得到新单词且该词要在字典中。求所有最少的变换路径。

解题思路:

更难于Leetcode 127,BFS用于找最短路径而DFS找路径,此题正是贯彻这一思想,先用BFS找出最短路径,
然后根据最短路径值找出所有路径。找BFS解的同时建图用邻接表表示Map<String, List<String>>(这是
部分图,与解相关的图)和解集合Map<String, Integer>(从始点到不同节点的最短距离),这两个信息正是
Dijkistra的图输入和解。DFS从始点开始遍历邻接节点,确保沿着最短路径走,最短路径为
map.get(cur)+1=map.get(next)表示当前节点到始点距离+1=儿节点到始点距离,终止条件为找到目标节点。

  1. 在遍历所有邻接节点的时候,如果不加筛选对所有邻接节点都做DFS会造成LTE。关键是要利用BFS中所有
    节点到单源的最短路径来剪枝。只需DFS最短路径上的节点,否则跳过。
  2. 利用了单源最短路径映射表distance后,不需要记录visited,因为重复的节点不会在最短路劲上。
  3. Cache nextWords的结果。

解题步骤:

这题是最短路径题,第一时间想到BFS。这是一条典型的单源最短路径问题。

  1. 建字典。
  2. BFS访问,得到图和单源最短路径Map,以及最短路径距离。同时建立邻接表graph[word] = neighbors,DFS时候不用再次找相邻单词
  3. DFS求路径,按最短路径剪枝dict[neighbor] == dict[startWord] + 1。

注意事项:

  1. 注意题目条件,开始词不在字典中(终结词默认在,否则无结果),要将它加入字典中且距离为1且要加入到path,Line 10。
  2. 建图的邻接表,对没有边的节点也要加到邻接表,所以先对所有点赋空列表,再根据边更新值,Line 29。用defaultdict(list)可解决
  3. DFS模板中去掉visited部分,因为用了最短距离distance的map来指导访问路径,所以不会存在循环的情况(否则不会是最短距离)
    而且如果有visited会存在丢解,因为如果一个节点不在最短路径上先被访问就会被标记为visited,真正到最短路径上时就会返回。
    DFS模板中加入if dict[neighbor] == dict[startWord] + 1来剪边。

Python代码:

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
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[int]]:
if not beginWord or not endWord:
return 0
distance, graph = {}, defaultdict(list)
for word in wordList:
distance[word] = 0
distance[beginWord] = 1
self.bfs(beginWord, endWord, distance, graph, set())
result = []
self.dfs(graph, beginWord, endWord, [beginWord], result, distance) # remember [beginWord]
return result

def dfs(self, graph, startWord, endWord, path, res, dict):
if startWord == endWord:
res.append(list(path))
return
'''if startWord in visited: # remember
return
visited.add(startWord)'''
for neighbor in graph[startWord]:
if dict[neighbor] == dict[startWord] + 1:
path.append(neighbor)
self.dfs(graph, neighbor, endWord, path, res, dict)
path.pop()

def bfs(self, beginWord, endWord, dict, graph, visited):
queue = deque([beginWord])
visited.add(beginWord)
# for key in dict.keys(): # remember
# graph[key] = []
while queue:
word = queue.popleft()
if word == endWord:
return dict[word]

neighbors = self.get_next_words(word, dict)
graph[word] = neighbors
for neighbor in neighbors:
if neighbor not in visited:
queue.append(neighbor)
visited.add(neighbor)
dict[neighbor] = dict[word] + 1
return 0

def get_next_words(self, word, dict):
res = []
for i in range(len(word)):
for c in string.ascii_lowercase: # or use 'abcdefghijklmnopqrstuvwxyz'
if c == word[i]:
continue
new_word = word[:i] + c + word[i + 1:]
if new_word in dict:
res.append(new_word)
return res

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
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<String> path = new ArrayList<>();
List<List<String>> res = new ArrayList<>();
if(beginWord == null || endWord == null)
return res;

// This is a dict and also keeps track of distance
Map<String, Integer> dict = getDict(wordList);
// Make sure endWord is in the dict and can be the next word
//dict.put(endWord, 0);
dict.put(beginWord, 1);
HashMap<String, List<String>> graph = new HashMap<String, List<String>>();
ladderLength(beginWord, endWord, dict, graph);
path.add(beginWord);
dfs(beginWord, endWord, dict, graph, path, res);
return res;
}

void dfs(String cur, String endWord, Map<String, Integer> distance,
HashMap<String, List<String>> graph, List<String> path, List<List<String>> res) {
if(endWord.equals(cur)) {
res.add(new ArrayList<>(path));
return;
}
for(String word : graph.get(cur)) {
path.add(word);
if(distance.get(word) - 1 == distance.get(cur)) // use distance, resolve LTE the most important
dfs(word, endWord, distance, graph, path, res);
path.remove(path.size() - 1);
}
}

// cache getNextWords
int ladderLength(String beginWord, String endWord, Map<String, Integer> dict, Map<String, List<String>> graph) {
Set<String> visited = new HashSet<>();
Queue<String> q = new LinkedList<>();
q.offer(beginWord);
visited.add(beginWord);
for(String s : dict.keySet()) {// remember
graph.put(s, new ArrayList<>());
}
while(!q.isEmpty()) {
String word = q.poll();
if(endWord.equals(word))
return dict.get(word);

List<String> nextWords = getNextWords(word, dict);
graph.put(word, new ArrayList<>(nextWords));
for(String s : nextWords) {
if(visited.contains(s))
continue;

q.offer(s);
visited.add(s);
dict.put(s, dict.get(word) + 1);
}
}
return 0;
}

Map<String, Integer> getDict(List<String> wordList) {
Map<String, Integer> map = new HashMap<>();
for(String word : wordList) {
map.put(word, 0);
}
return map;
}

List<String> getNextWords(String word, Map<String, Integer> dict) {
List<String> result = new ArrayList<>();
for(int i = 0; i < word.length(); i++) {
for(int j = 0; j < 26; j++) {
char newChar = (char)('a' + j);
if(word.charAt(i) == newChar) // exclude itself
continue;
String newWord = word.substring(0, i) +
newChar + word.substring(i + 1, word.length());
if(dict.containsKey(newWord))
result.add(newWord);

}
}
return result;
}

算法分析:

getNextWords是L26L=<code>O(L<sup>2</sup>)</code>产生新字符串需要L
时间复杂度为<code>O(n*L<sup>2</sup> + m*k)</code>,空间复杂度O(n),m为答案个数, k为最短路径值,n为单词数。

LeetCode 368 Largest Divisible Subset

Given a set of distinct positive integers, find the largest subset such that every pair (S<sub>i</sub>, S<sub>j</sub>) of elements in this subset satisfies:

S<sub>i</sub> % S<sub>j</sub> = 0 or S<sub>j</sub> % S<sub>i</sub> = 0.

If there are multiple solutions, return any subset is fine.

Example 1:

<div>

<pre>Input: <span id="example-input-1-1">[1,2,3]</span> Output: <span id="example-output-1">[1,2]</span> (of course, [1,3] will also be ok) </pre>

<div>

Example 2:

<pre>Input: <span id="example-input-2-1">[1,2,4,8]</span> Output: <span id="example-output-2">[1,2,4,8]</span> </pre>

题目大意:

一个数组,让我们求这样一个子集合,集合中的任意两个数相互取余均为0。

解题思路:

由于知道子问题有助于求解考虑用DP。它就是LIS的翻版。这道题还需要打印DP路径。

  1. 定义dp[i]为num[i-1]这个数对应的最大可整除子集合个数。
  2. 递归式为dp[i] = max{dp[j-1] + 1}, 0<j<i, 若num[i-1]可被num[j-1]整除
  3. 方向为从左到右。初始值为dp = 1。
  4. path数组记录解的下标+1,每求得一个解dp[i] = dp[j] + 1就记录对应上一层解的下标,也就是到此解的路径。

注意事项:

  1. 初始值dp = 1。

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
public List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> res = new ArrayList<>();
if(nums == null || nums.length == 0)
return res;
if(nums.length == 1)
return Arrays.asList(nums[0]);
Arrays.sort(nums);
int max = Integer.MIN_VALUE;
int maxPos = -1;
int[] dp = new int[nums.length + 1];
int[] path = new int[nums.length + 1];
for(int i = 0; i < dp.length; i++) // remember to init to 1
dp[i] = 1;
for(int i = 1; i < dp.length; i++) {
for(int j = 1; j < i; j++) {
if(nums[i-1] % nums[j-1] == 0 && dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
path[i] = j;
}
}
if(dp[i] > max) { // the biggest value might not be the last one, keep track of the start pos for the path
max = dp[i];
maxPos = i;
}
}
int pos = maxPos;
for(int i = 0; i < dp[maxPos]; i++) {
res.add(nums[pos-1]);
pos = path[pos];

}
Collections.sort(res);
return res;
}

算法分析:

时间复杂度为<code>O(n<sup>2</sup>)</code>,空间复杂度<code>O(n<sup>2</sup>)</code>。

Free mock interview