0%

Intersection of Two Arrays

Given two arrays, write a function to compute their intersection.

Example 1:

1
2
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2]

Example 2:

1
2
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [9,4]

Note:

  • Each element in the result must be unique.
  • The result can be in any order.

题意分析

找出两个数组的交集,不带重复元素。自然想到利用set的特性。首先遍历其中一个数组,将元素不重合的添加到set中,然后对第二个数组做遍历,若set含有这个元素,则加入到结果的set集合中,最后将结果set转换为数组。

代码实现

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
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
// init a set which contains all numbers in nums1
Set<Integer> set = new HashSet<>();
for(int num: nums1) {
set.add(num);
}

// The set expression of the result
Set<Integer> aux_set = new HashSet<>();
for(int num : nums2) {
if(set.contains(num)) {
aux_set.add(num);
}
}

// Convert the set to array
int[] res = new int[aux_set.size()];
int i = 0;
for(int num : aux_set) {
res[i++] = num;
}
return res;
}
}

Sort colors

Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

Note: You are not suppose to use the library’s sort function for this problem.

Example:

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

Follow up:

A rather straight forward solution is a two-pass algorithm using counting sort.
First, iterate the array counting number of 0’s, 1’s, and 2’s, then overwrite array with total number of 0’s, then 1’s and followed by 2’s.
Could you come up with a one-pass algorithm using only constant space?

题意分析

该题就是所谓的荷兰国旗问题,红白蓝三色排序。我们对数组进行遍历,将1当作pivot,类似快排。设定两个指针,lt和gt,若该数字为0,说明应在左侧,将lt和当前位置数字做交换。若该数字为1,说明数字大于pivot,则应与gt做交换。若相等,只需要继续遍历而不需要做交换。终止条件是遍历变量i大于gt,遍历完所有元素。由于只遍历数组,所以时间复杂度为O(n)。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public void sortColors(int[] nums) {
if(nums == null || nums.length == 1) return;
int lt = 0;
int gt = nums.length - 1;
int i = 0;
while(i <= gt){
if(nums[i] > 1) swap(nums, i, gt--);
else if(nums[i] < 1) swap(nums, i++, lt++);
else i++;
}
}
private void swap(int[] arr, int i, int j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}

Merge Intervals

Given a collection of intervals, merge all overlapping intervals.

Example 1:

1
2
3
Input: [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].

Example 2:

1
2
3
Input: [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considerred overlapping.

分析题意

该题让我们合并有交集的interval,首先利用start的大小对整个集合排序。然后对集合做遍历,若一个interval的start大于前面的end值说明存在overlap,需要将end值设为当前end和原来end二者中的最大值。否则说明interval是离散的,只需要将之前的start,end实例化为一个新的Interval实例,然后加入到集合,并初始化新的start和end值。遍历结束之后将最后一个start,end的interval加入到集合当中。

代码实现

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
/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
* }
*/
class Solution {
public List<Interval> merge(List<Interval> intervals) {
if(intervals == null || intervals.size() <= 1) return intervals;

intervals.sort((i1, i2) -> i1.start - i2.start);
List<Interval> res = new ArrayList<>();
int start = intervals.get(0).start;
int end = intervals.get(0).end;

for(Interval interval : intervals) {
// show this interval overlaps
if(interval.start <= end) end = Math.max(end, interval.end);
else {
// the interval disjoints
res.add(new Interval(start, end));
start = interval.start;
end = interval.end;
}
}
// The last interval hasn't been added
res.add(new Interval(start, end));
return res;
}
}

Wiggle sort

Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3]
For example, given nums = [3, 5, 2, 1, 6, 4], one possible answer is [1, 6, 2, 5, 3, 4].

分析题意

给定题目,可以观察到从1位置开始的偶数位置的数字都大于等于前一个位置的数字,而奇数位置的数字都小于等于前一个数字,由此可以遍历数组,若遇到奇数位置且其数字大于前一个数字或者偶数位置的数字小于前一个位置的数字,那么将两者做交换处理。由于遍历数组只有交换操作,可知时间复杂度为O(n)。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
public class Solution {
public void wiggleSort(int[] nums) {
if(nums.length < 2) return;
for(int i = 1; i < nums.length; i++) {
if((i & 1) == 1 && nums[i] < nums[i - 1] || (i & 1) == 0 && nums[i] > nums[i - 1]) {
int t = nums[i];
nums[i] = nums[i - 1];
nums[i - 1] = t;
}
}
}
}

H-Index

Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher’s h-index.

According to the definition of h-index on Wikipedia: “A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each.”

Example:

1
2
3
4
5
6
Input: citations = [3,0,6,1,5]
Output: 3
Explanation: [3,0,6,1,5] means the researcher has 5 papers in total and each of them had
received 3, 0, 6, 1, 5 citations respectively.
Since the researcher has 3 papers with at least 3 citations each and the remaining
two with no more than 3 citations each, her h-index is 3.

Note: If there are several possible values for h, the maximum one is taken as the h-index.

题意分析

该题是要从给出的citations数组中分析出一个数字,数组的有大于等于该数字的项数,他们的值大于等于该数字。思路就是构造一个citations出现次数数组,即代码中的aux,我们再从后向前遍历该数组,每次遍历加上citation出现的次数,若某轮出现累计的次数和大于等于循环变量i,那么我们就找到了这个数字。否则不存在这样的数字,返回0。只涉及到数组单层遍历,时间复杂度为O(N)。

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int hIndex(int[] citations) {
if(citations == null || citations.length == 0) return 0;
int length = citations.length;
int[] aux = new int[length + 1];

for(int i = 0; i < length; i++) {
if(citations[i] >= length) aux[length]++;
else aux[citations[i]]++;
}

int t = 0;
for(int i = length; i >= 0; i--) {
t += aux[i];
if(t >= i) return i;
}
return 0;
}
}

Largest Number

Given a list of non negative integers, arrange them such that they form the largest number.

Example 1:

1
2
Input: [10,2]
Output: "210"

Example 2:

1
2
Input: [3,30,34,5,9]
Output: "9534330"

Note: The result may be very large, so you need to return a string instead of an integer.

分析题意

这道题难度不大,主要考察的还是Comparator接口的使用方法。我们需要通过该接口重新定义比较机制。假定数组长度为n的话,数组中平均字符串长为k,比较2个字符串花费O(k)时间,排序花费O(nlogn),向StringBuilder中追加字符串花费O(n),所以总花费为O(nklognk) + O(n) = O(nklognk),空间复杂度O(n)。

代码实现

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
class Solution {
public String largestNumber(int[] nums) {
if(nums == null || nums.length == 0) return "";
String[] s_num = new String[nums.length];
// Convert num array to string array
for(int i = 0; i < nums.length; i++)
s_num[i] = String.valueOf(nums[i]);
Comparator<String> cm = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
String s1 = o1 + o2;
String s2 = o2 + o1;
return s2.compareTo(s1);
}
};
Arrays.sort(s_num, cm);
// Extreme case when the nums is all zero
if(s_num[0].charAt(0) == '0') return "0";

StringBuilder sb = new StringBuilder();
for(String s : s_num)
sb.append(s);
return sb.toString();
}
}

Sort List

O(nlog n) time and O(1) space

分析题意

由于nlogn的时间复杂度,很自然想到归并排序。归并排序可以自顶向下进行归并,也可以自底向上归并。对于数组来说,自顶向下的归并排序时间复杂度nlogn,空间复杂度为n长度的辅助数组和logn深度的递归深度(n+logn),对于自底向上的归并排序,时间复杂度相同,空间复杂度去除了logn的递归深度栈。而对于链表的归并排序,时间复杂度相同,而由于链表不需要额外的辅助数组,所以自顶向下的空间复杂度为logn,自底向上的空间复杂度为O(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
    /**
    * Definition for singly-linked list.
    * public class ListNode {
    * int val;
    * ListNode next;
    * ListNode(int x) { val = x; }
    * }
    */
    class Solution {
    public ListNode sortList(ListNode head) {
    if (head == null || head.next == null) return head;
    ListNode slow = head;
    ListNode fast = head.next;
    while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
    }
    ListNode mid = slow.next;
    slow.next = null;
    return merge(sortList(head), sortList(mid));
    }

    private ListNode merge(ListNode l1, ListNode l2) {
    ListNode dummyNode = new ListNode(0);
    ListNode tail = dummyNode;

    while (l1 != null && l2 != null) {
    if (l1.val > l2.val) {
    ListNode temp = l1;
    l1 = l2;
    l2 = temp;
    }
    tail.next = l1;
    l1 = l1.next;
    tail = tail.next;
    }
    tail.next = (l1 == null) ? l2 : l1;
    return dummyNode.next;
    }
    }
  • 自底向上的归并排序
    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
    /**
    * Definition for singly-linked list.
    * public class ListNode {
    * int val;
    * ListNode next;
    * ListNode(int x) { val = x; }
    * }
    */
    class Solution {
    public ListNode sortList(ListNode head) {
    if (head == null || head.next == null) return head;
    int length = 0;
    for (ListNode l = head; l != null; l = l.next) length++;

    ListNode dummyNode = new ListNode(0);
    dummyNode.next = head;
    ListNode l;
    ListNode r;
    ListNode tail;
    for (int size = 1; size < length; size *= 2) {
    ListNode cur = dummyNode.next;
    tail = dummyNode;
    while (cur != null) {
    l = cur;
    r = split(l, size);
    cur = split(r, size);
    Pair p = merge(l, r);
    tail.next = p.first;
    tail = p.second;
    }
    }
    return dummyNode.next;
    }

    private ListNode split(ListNode head, int n) {
    while (--n > 0 && head != null) {
    head = head.next;
    }
    ListNode rest = (head != null) ? head.next : null;
    if (head != null) head.next = null;
    return rest;
    }

    private Pair merge(ListNode l1, ListNode l2) {
    ListNode dummyNode = new ListNode(0);
    ListNode tail = dummyNode;
    while (l1 != null && l2 != null) {
    if (l1.val > l2.val) {
    ListNode temp = l1;
    l1 = l2;
    l2 = temp;
    }
    tail.next = l1;
    l1 = l1.next;
    tail = tail.next;
    }
    tail.next = (l1 == null) ? l2 : l1;
    while (tail.next != null) tail = tail.next;
    return new Pair(dummyNode.next, tail);
    }

    private class Pair {
    ListNode first;
    ListNode second;
    Pair(ListNode f, ListNode s) {first = f; second = s;}
    }
    }

Insertion sort list

Sort a linked list using insertion sort.

Example 1:

1
2
Input: 4->2->1->3
Output: 1->2->3->4

Example 2:

1
2
Input: -1->5->3->4->0
Output: -1->0->3->4->5

分析题意

相比于原来数组的插入排序而言,该问题困难在对于链表的插入排序,需要利用多个指针保持对链表的访问。思路是:对于basic case,链表为null或只有单个元素,那么链表有序。否则,要先越过链表前部已有序的序列,然后遇到第一个逆序,那么需要利用多个指针将该逆序调整,小数插入到后面合适的位置。而这个合适的位置需要通过从dummyNode向前遍历完成,需要注意的就是前面和后面两个地方的指针修改,谨慎操作。

代码实现

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
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode insertionSortList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;

while (head != null && head.next != null) {
// 越过链表前部有序的部分
if (head.val <= head.next.val) head = head.next;
else {
// 预备插入操作
ListNode temp = head.next;
head.next = temp.next;

// 从dummyNode的下一个开始遍历链表找到第一个大于要插入节点的位置
ListNode cur = dummyNode;
while (cur.next.val <= temp.val) {
cur = cur.next;
}
temp.next = cur.next;
cur.next = temp;
}
}
return dummyNode.next;
}
}

Surrounded Regions

Given a 2D board containing ‘X’ and ‘O’ (the letter O), capture all regions surrounded by ‘X’.

A region is captured by flipping all ‘O’s into ‘X’s in that surrounded region.

Example:

1
2
3
4
X X X X
X O O X
X X O X
X O X X

After running your function, the board should be:

1
2
3
4
X X X X
X X X X
X X X X
X O X X

Explanation:

Surrounded regions shouldn’t be on the border, which means that any ‘O’ on the border of the board are not flipped to ‘X’. Any ‘O’ that is not on the border and it is not connected to an ‘O’ on the border will be flipped to ‘X’. Two cells are connected if they are adjacent cells connected horizontally or vertically.

分析题意

这道题的tag是union_find,所以理所应当的想到用union_find的数据结构去理解本题。题意是对于任何在图中非外围的O以及内层与外层O连通的O,将O置换为X。扫描整个二维数组,将外层O连接到一个dummynode,然后对于内层的O,若其上下左右存在O,就连通到其相应的O。如此扫描过后,再遍历二维数组,检查那些不与dummynode连通的O,将其置换为X,问题得解。

代码实现

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
class Solution {
int rows, cols;
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
rows = board.length;
cols = board[0].length;

WeightedQuickUnionUF uf = new WeightedQuickUnionUF(rows * cols + 1);
int dummyNode = rows * cols;
// 扫描二维数组将外层O连接至dummynode,将内层O作相应连接处理
for(int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (board[i][j] == 'O') {
if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) {
uf.union(node(i, j), dummyNode);
}
else {
if (i > 0 && board[i - 1][j] == 'O') uf.union(node(i - 1, j), node(i, j));
if (i < rows - 1 && board[i + 1][j] == 'O') uf.union(node(i + 1, j), node(i, j));
if (j > 0 && board[i][j - 1] == 'O') uf.union(node(i, j - 1), node(i, j));
if (j < cols - 1 && board[i][j + 1] == 'O') uf.union(node(i, j + 1), node(i ,j));
}
}
}
}
// 二次遍历该方阵,将未连接至dummynode的O做替换。
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (board[i][j] == 'O' && !uf.connected(node(i, j), dummyNode)) {
board[i][j] = 'X';
}
}
}
}

private int node(int i, int j) {
return i * cols + j;
}

// 带权重的快速联合数据结构
private class WeightedQuickUnionUF {
private int[] parent;
private int[] size;
private int count;

public WeightedQuickUnionUF (int n) {
count = n;
parent = new int[n];
size = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}

public int count() {return count;}

public int find(int p) {
while (p != parent[p])
p = parent[p];
return p;
}

public boolean connected (int p, int q) {
return find(p) == find(q);
}

public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) return;

// make smaller root point to larger one
if (size[rootP] < size[rootQ]) {
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
} else {
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
}
count--;
}
}
}

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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
import org.junit.Test;
import static org.junit.Assert.*;

/**
* A Generic heap class. Unlike Java's priority queue, this heap doesn't just
* store Comparable objects. Instead, it can store any type of object
* (represented by type T), along with a priority value. Why do it this way? It
* will be useful later on in the class...
*/
public class ArrayHeap<T> implements ExtrinsicPQ<T> {
private Node[] contents;
private int size;

public ArrayHeap() {
contents = new ArrayHeap.Node[16];

/* Add a dummy item at the front of the ArrayHeap so that the getLeft,
* getRight, and parent methods are nicer. */
contents[0] = null;

/* Even though there is an empty spot at the front, we still consider
* the size to be 0 since nothing has been inserted yet. */
size = 0;
}

/**
* Returns the index of the node to the left of the node at i.
*/
private static int leftIndex(int i) {
/* TODO: Your code here! */
return 2 * i;
}

/**
* Returns the index of the node to the right of the node at i.
*/
private static int rightIndex(int i) {
/* TODO: Your code here! */
return 2 * i + 1;
}

/**
* Returns the index of the node that is the parent of the node at i.
*/
private static int parentIndex(int i) {
/* TODO: Your code here! */
return i / 2;
}

/**
* Gets the node at the ith index, or returns null if the index is out of
* bounds.
*/
private Node getNode(int index) {
if (!inBounds(index)) {
return null;
}
return contents[index];
}

/**
* Returns true if the index corresponds to a valid item. For example, if
* we have 5 items, then the valid indices are 1, 2, 3, 4, 5. Index 0 is
* invalid because we leave the 0th entry blank.
*/
private boolean inBounds(int index) {
if ((index > size) || (index < 1)) {
return false;
}
return true;
}

/**
* Swap the nodes at the two indices.
*/
private void swap(int index1, int index2) {
Node node1 = getNode(index1);
Node node2 = getNode(index2);
contents[index1] = node2;
contents[index2] = node1;
}


/**
* Returns the index of the node with smaller priority. Precondition: not
* both nodes are null.
*/
private int min(int index1, int index2) {
Node node1 = getNode(index1);
Node node2 = getNode(index2);
if (node1 == null) {
return index2;
} else if (node2 == null) {
return index1;
} else if (node1.myPriority < node2.myPriority) {
return index1;
} else {
return index2;
}
}


/**
* Bubbles up the node currently at the given index.
*/
private void swim(int index) {
// Throws an exception if index is invalid. DON'T CHANGE THIS LINE.
validateSinkSwimArg(index);

/** TODO: Your code here. */
while (index > 1 && (getNode(index).myPriority) < (getNode(parentIndex(index)).myPriority) ) {
swap(index, parentIndex(index));
index /= 2;
}
}

/**
* Bubbles down the node currently at the given index.
*/
private void sink(int index) {
// Throws an exception if index is invalid. DON'T CHANGE THIS LINE.
validateSinkSwimArg(index);

/** TODO: Your code here. */
while (2 * index <= size) {
int j = 2 * index;
if (j < size && (getNode(j).myPriority > getNode(j+1).myPriority)) j++;
if (getNode(index).myPriority < getNode(j).myPriority) break;
swap(index, j);
index = j;
}
}

/**
* Inserts an item with the given priority value. This is enqueue, or offer.
* To implement this method, add it to the end of the ArrayList, then swim it.
*/
@Override
public void insert(T item, double priority) {
/* If the array is totally full, resize. */
if (size + 1 == contents.length) {
resize(contents.length * 2);
}

/* TODO: Your code here! */
contents[++size] = new Node(item, priority);
swim(size);
}

/**
* Returns the Node with the smallest priority value, but does not remove it
* from the heap. To implement this, return the item in the 1st position of the ArrayList.
*/
@Override
public T peek() {
/* TODO: Your code here! */
return contents[1].myItem;
}

/**
* Returns the Node with the smallest priority value, and removes it from
* the heap. This is dequeue, or poll. To implement this, swap the last
* item from the heap into the root position, then sink the root. This is
* equivalent to firing the president of the company, taking the last
* person on the list on payroll, making them president, and then demoting
* them repeatedly. Make sure to avoid loitering by nulling out the dead
* item.
*/
@Override
public T removeMin() {
/* TODO: Your code here! */
T min = peek();
swap(1, size);
size--;
contents[size + 1] = null;
sink(1);

return min;
}

/**
* Returns the number of items in the PQ. This is one less than the size
* of the backing ArrayList because we leave the 0th element empty. This
* method has been implemented for you.
*/
@Override
public int size() {
return size;
}

/**
* Change the node in this heap with the given item to have the given
* priority. You can assume the heap will not have two nodes with the same
* item. Check item equality with .equals(), not ==. This is a challenging
* bonus problem, but shouldn't be too hard if you really understand heaps
* and think about the algorithm before you start to code.
*/
@Override
public void changePriority(T item, double priority) {
/* TODO: Your code here! */
for (int i = 1; i <= size; i++) {
if (contents[i].item().equals(item)) {
contents[i].myPriority = priority;
if (priority < contents[parentIndex(i)].myPriority) {
swim(i);
} else if (priority > contents[leftIndex(i)].myPriority || priority > contents[rightIndex(i)].myPriority) {
sink(i);
}
}
}
}

/**
* Prints out the heap sideways. Provided for you.
*/
@Override
public String toString() {
return toStringHelper(1, "");
}

/* Recursive helper method for toString. */
private String toStringHelper(int index, String soFar) {
if (getNode(index) == null) {
return "";
} else {
String toReturn = "";
int rightChild = rightIndex(index);
toReturn += toStringHelper(rightChild, " " + soFar);
if (getNode(rightChild) != null) {
toReturn += soFar + " /";
}
toReturn += "\n" + soFar + getNode(index) + "\n";
int leftChild = leftIndex(index);
if (getNode(leftChild) != null) {
toReturn += soFar + " \\";
}
toReturn += toStringHelper(leftChild, " " + soFar);
return toReturn;
}
}


/**
* Throws an exception if the index is invalid for sinking or swimming.
*/
private void validateSinkSwimArg(int index) {
if (index < 1) {
throw new IllegalArgumentException("Cannot sink or swim nodes with index 0 or less");
}
if (index > size) {
throw new IllegalArgumentException("Cannot sink or swim nodes with index greater than current size.");
}
if (contents[index] == null) {
throw new IllegalArgumentException("Cannot sink or swim a null node.");
}
}

private class Node {
private T myItem;
private double myPriority;

private Node(T item, double priority) {
myItem = item;
myPriority = priority;
}

public T item(){
return myItem;
}

public double priority() {
return myPriority;
}

@Override
public String toString() {
return myItem.toString() + ", " + myPriority;
}
}


/** Helper function to resize the backing array when necessary. */
private void resize(int capacity) {
Node[] temp = new ArrayHeap.Node[capacity];
for (int i = 1; i < this.contents.length; i++) {
temp[i] = this.contents[i];
}
this.contents = temp;
}

@Test
public void testIndexing() {
assertEquals(6, leftIndex(3));
assertEquals(10, leftIndex(5));
assertEquals(7, rightIndex(3));
assertEquals(11, rightIndex(5));

assertEquals(3, parentIndex(6));
assertEquals(5, parentIndex(10));
assertEquals(3, parentIndex(7));
assertEquals(5, parentIndex(11));
}

@Test
public void testSwim() {
ArrayHeap<String> pq = new ArrayHeap<>();
pq.size = 7;
for (int i = 1; i <= 7; i += 1) {
pq.contents[i] = new ArrayHeap<String>.Node("x" + i, i);
}
// Change item x6's priority to a low value.

pq.contents[6].myPriority = 0;
System.out.println("PQ before swimming:");
System.out.println(pq);

// Swim x6 upwards. It should reach the root.

pq.swim(6);
System.out.println("PQ after swimming:");
System.out.println(pq);
assertEquals("x6", pq.contents[1].myItem);
assertEquals("x2", pq.contents[2].myItem);
assertEquals("x1", pq.contents[3].myItem);
assertEquals("x4", pq.contents[4].myItem);
assertEquals("x5", pq.contents[5].myItem);
assertEquals("x3", pq.contents[6].myItem);
assertEquals("x7", pq.contents[7].myItem);
}

@Test
public void testSink() {
ArrayHeap<String> pq = new ArrayHeap<>();
pq.size = 7;
for (int i = 1; i <= 7; i += 1) {
pq.contents[i] = new ArrayHeap<String>.Node("x" + i, i);
}
// Change root's priority to a large value.
pq.contents[1].myPriority = 10;
System.out.println("PQ before sinking:");
System.out.println(pq);

// Sink the root.
pq.sink(1);
System.out.println("PQ after sinking:");
System.out.println(pq);
assertEquals("x2", pq.contents[1].myItem);
assertEquals("x4", pq.contents[2].myItem);
assertEquals("x3", pq.contents[3].myItem);
assertEquals("x1", pq.contents[4].myItem);
assertEquals("x5", pq.contents[5].myItem);
assertEquals("x6", pq.contents[6].myItem);
assertEquals("x7", pq.contents[7].myItem);
}


@Test
public void testInsert() {
ArrayHeap<String> pq = new ArrayHeap<>();
pq.insert("c", 3);
assertEquals("c", pq.contents[1].myItem);

pq.insert("i", 9);
assertEquals("i", pq.contents[2].myItem);

pq.insert("g", 7);
pq.insert("d", 4);
assertEquals("d", pq.contents[2].myItem);

pq.insert("a", 1);
assertEquals("a", pq.contents[1].myItem);

pq.insert("h", 8);
pq.insert("e", 5);
pq.insert("b", 2);
pq.insert("c", 3);
pq.insert("d", 4);
System.out.println("pq after inserting 10 items: ");
System.out.println(pq);
assertEquals(10, pq.size());
assertEquals("a", pq.contents[1].myItem);
assertEquals("b", pq.contents[2].myItem);
assertEquals("e", pq.contents[3].myItem);
assertEquals("c", pq.contents[4].myItem);
assertEquals("d", pq.contents[5].myItem);
assertEquals("h", pq.contents[6].myItem);
assertEquals("g", pq.contents[7].myItem);
assertEquals("i", pq.contents[8].myItem);
assertEquals("c", pq.contents[9].myItem);
assertEquals("d", pq.contents[10].myItem);
}


@Test
public void testInsertAndRemoveOnce() {
ArrayHeap<String> pq = new ArrayHeap<>();
pq.insert("c", 3);
pq.insert("i", 9);
pq.insert("g", 7);
pq.insert("d", 4);
pq.insert("a", 1);
pq.insert("h", 8);
pq.insert("e", 5);
pq.insert("b", 2);
pq.insert("c", 3);
pq.insert("d", 4);
String removed = pq.removeMin();
assertEquals("a", removed);
assertEquals(9, pq.size());
assertEquals("b", pq.contents[1].myItem);
assertEquals("c", pq.contents[2].myItem);
assertEquals("e", pq.contents[3].myItem);
assertEquals("c", pq.contents[4].myItem);
assertEquals("d", pq.contents[5].myItem);
assertEquals("h", pq.contents[6].myItem);
assertEquals("g", pq.contents[7].myItem);
assertEquals("i", pq.contents[8].myItem);
assertEquals("d", pq.contents[9].myItem);
}

@Test
public void testInsertAndRemoveAllButLast() {
ExtrinsicPQ<String> pq = new ArrayHeap<>();
pq.insert("c", 3);
pq.insert("i", 9);
pq.insert("g", 7);
pq.insert("d", 4);
pq.insert("a", 1);
pq.insert("h", 8);
pq.insert("e", 5);
pq.insert("b", 2);
pq.insert("c", 3);
pq.insert("d", 4);

int i = 0;
String[] expected = {"a", "b", "c", "c", "d", "d", "e", "g", "h", "i"};
while (pq.size() > 1) {
assertEquals(expected[i], pq.removeMin());
i += 1;
}
}

}