IEEE International Conference on Distributed Computing Systems | ICDCS provides a forum for engineers and scientists in academia, industry, and government to present and discuss their latest research findings on a broad array of topics in distributed computing. This is the oldest conference in the field of distributed computing systems | https://icdcs2021.us/ |

IEEE Int’l Conf. on Cluster Computing | The IEEE Cluster Conference serves as a major international forum for presenting and sharing recent accomplishments and technological developments in the field of cluster computing as well as the use of cluster systems for scientific and commercial applications. | https://clustercomp.org/2021/ |

International Conference on Parallel and Distributed Computing, Applications and Technologies（PDCAT） | PDCAT is a major forum for scientists, engineers, and practitioners throughout the world to present the latest research, results, ideas, developments and applications in all areas of parallel and distributed computing. | http://www.wikicfp.com/cfp/servlet/event.showcfp?eventid=86503©ownerid=1 |

IEEE International Parallel and Distributed Processing Symposium（IPDPS） | IPDPS is an international forum for engineers and scientists from around the world to present their latest research findings in all aspects of parallel computation. | https://www.ipdps.org/ |

PODC: Annual ACM Symposium on Principles of Distributed Computing | The ACM Symposium on Principles of Distributed Computing is an international forum on the theory, design, analysis, implementation and application of distributed systems and networks. | https://www.podc.org/ |

ICPADS – International Conference on Parallel and Distributed Systems | ICPADS provides an international forum for scientists, engineers and users to exchange and share their experiences, new ideas, and latest research results on all aspects of parallel and distributed systems. Contributions are solicited in all areas of parallel and distributed systems research and applications. | https://icpads2020.comp.polyu.edu.hk/ |

ICDCS: IEEE International Conference on Distributed Computing Systems | The annual ICDCS conference is a premier international forum for researchers, developers and users to present, discuss and exchange the cutting edge ideas and latest findings on topics related to any aspects of distributed computing systems. | https://icdcs2021.us/ |

IPDPS: IEEE International Parallel and Distributed Processing Symposium | IPDPS is an international forum for engineers and scientists from around the world to present their latest research findings in all aspects of parallel computation. | https://www.ipdps.org/ |

Fortunately, I found this MIT open course. This course systematically helps you go through 8 areas, so that you can master these important tools more systematically.

These areas include:

- Shell
- Vim
- Data Wrangling
- Command-line Environment
- Version Control (Git)
- Debugging and Profiling
- Metaprogramming
- Security and Cryptography

Course link: https://missing.csail.mit.edu/

]]>The good news? It always happens to the best of us. Here’s something I’d like to share.

Most interview algorithms are adopted from some coding practice websites like leetcode, codeforce, etc. On these websites, each problem has a runtime limitation, and this is what we can cheat on.

At most cases, an allowed executing time for a problem is 1 or 2 seconds, and we know that a cpu could calculate about 10^8 times per second. So We can guess a problem solution’r big O from input test case range because we have to write a program that is able to finish in 1 second.

The following is the cheating sheet.

n <= 30, Exponential | DFS |

n <= 100, O(n^3) | Dp, Floyed |

n <= 1000, O(n^2)/O(nlogn) | DP, Binary Search |

n <= 10^5, O(nlogn) | Binary Search, Heap, Map/Set, Binary Indexed Tree |

n <= 10^6, O(n) | Two Pointers, Hash, KMP, Union Find, Heap, Dijkstra |

n <= 10^9 | mathematical Problem |

What I want to remind you is this does not apply to all questions. We don’t want to get stuck in real interviews. So, practice more interview questions on leetcode, and it gets easier and faster.

]]>Bidirectional BFS

Set two queues, src queue and dest queue. Init src queue with input board, and dest queue with final state [[1,2,3],[4,5,0]].

When both queues are not empty, expand the queue with smaller size until searching process meet at some point where expansion from src finds a state has been discovered by dest direction.

```
class Solution {
public int slidingPuzzle(int[][] board) {
if(toInt(board) == 123450) return 0;
Queue<int[][]> srcQ = new LinkedList();
Queue<int[][]> destQ = new LinkedList();
HashMap<Integer, Integer> srcSteps = new HashMap();
HashMap<Integer, Integer> destSteps = new HashMap();
srcQ.offer(board);
destSteps.put(toInt(new int[][]{{1,2,3},{4,5,0}}), 0);
destQ.offer(new int[][]{{1,2,3},{4,5,0}});
srcSteps.put(toInt(board), 0);
int step = -1;
while(srcQ.size() > 0 && destQ.size() > 0 ) {
if (srcQ.size() <= destQ.size()) {
step = expand(srcQ, srcSteps, destSteps);
} else {
step = expand(destQ, destSteps, srcSteps);
}
if (step != -1) {
return step;
}
}
return step;
}
private int expand(Queue<int[][]> q, HashMap<Integer, Integer> src, HashMap<Integer, Integer> dest) {
int steps = -1;
int[][] cur = q.poll();
int[][] dirs = new int[][]{{0,1},{0, -1}, {1, 0}, {-1, 0}};
for (int i = 0; i < 2; i++) {
for(int j = 0; j < 3; j++) {
if (cur[i][j] == 0) {
for (int[] dir : dirs) {
int nx = i + dir[0];
int ny = j + dir[1];
int[][] tmp = new int[2][3];
for(int x = 0; x < 2; x++) {
for (int y = 0; y < 3; y++) {
tmp[x][y] = cur[x][y];
}
}
if (nx >= 0 && nx < 2 && ny >= 0 && ny < 3 ) {
tmp[i][j] = tmp[nx][ny];
tmp[nx][ny] = 0;
//System.out.println(toInt(tmp));
if (dest.get(toInt(tmp)) != null) {
return dest.get(toInt(tmp)) + src.get(toInt(cur)) + 1;
}
if (src.get(toInt(tmp)) != null) {
continue;
}
src.put(toInt(tmp), src.get(toInt(cur)) + 1);
q.offer(tmp);
}
}
}
}
}
return steps;
}
private int toInt(int[][] board){
int ans = 0;
for(int i = 0; i < 2; i++) {
for(int j= 0; j < 3; j++) {
ans = ans * 10 + board[i][j];
}
}
return ans;
}
}
```

]]>A similar question is Leetcode 493, counting reverse pairs. A data structure “Binary Indexed Tree”, BIT, would help.

Steps:

- Calculate prefix sum. -> sum[]
- Work out all lower bounds and upper bounds for each sum element. -> lowerBounds[], upperBounds[]
- all[] = unique(sum[] + lowerBounds[] + upperBounds[])
- discretization
- For each element sum[i], count the times of elements between lowerBounds[i] and upperBounds[i] occurred.

```
class Solution {
int N;
int[] c;
long[] sum;
long[] lowerBound;
long[] upperBound;
long[] all;
private int low_bit(int x) {
return x & -x;
}
private void add(int x, int v) {
while (x <= N) {
c[x] += v;
x += low_bit(x);
}
}
private int query(int x) {
int ans = 0;
while (x > 0) {
ans += c[x];
x -= low_bit(x);
}
return ans;
}
public int countRangeSum(int[] nums, int lower, int upper) {
if (nums.length == 0) return 0;
prepare(nums, lower, upper);
//discretization
HashMap<Long, Integer> map = new HashMap();
for(int i = 0; i < all.length; i++) map.put(all[i], i + 1);
int ans = 0;
add(map.get((long)0), 1);
for(int i = 1; i < sum.length; i++) {
ans += query(map.get(upperBound[i])) - query(map.get(lowerBound[i])-1);
add(map.get(sum[i]), 1);
}
return ans;
}
private void prepare(int[] nums, int lower, int upper) {
sum = new long[nums.length + 1];
lowerBound = new long[nums.length + 1];
upperBound = new long[nums.length + 1];
//unique elements
HashSet<Long> allSet = new HashSet();
allSet.add( (long)0);
for (int i = 1; i <= nums.length; i++) {
sum[i] = sum[i-1] + nums[i-1];
allSet.add(sum[i]);
allSet.add(sum[i] - lower);
allSet.add(sum[i] - upper);
lowerBound[i] = sum[i] - upper;
upperBound[i] = sum[i] - lower;
}
all = new long[allSet.size()];
this.c = new int[allSet.size() + 1];
this.N = allSet.size();
int idx = 0;
for(long x : allSet) {
all[idx++] = x;
}
Arrays.sort(all);
}
}
```

]]>If you love tropical scene with blue sky, book a ticker to there right now!

]]>Official solutions have several approaches including sorting, heap, and quick selecting. They are all great. I’d like to put forward another solution: Binary Search.

First, we can come to that the answer must be equal to or greater than the MIN element and equal to or smaller than the MAX element in the array. That is to say, the range of the answer is [min, max].

So, now let’s try to convert this problem into a decision one. By observing, we can find out that for a given x, if x is kth greatest element, there only k-1 elements are grater than x. For example, in array

`[3,2,1,5,6,4] `

If I guess, 5 is 2nd greatest element, then I can only find one element 6 is greater than 5.

That is to say, for a given x, if there are k elements >= x, we should guess another bigger x.

```
class Solution {
int[] nums;
int k;
public int findKthLargest(int[] nums, int k) {
this.nums = nums;
this.k = k;
int l = Integer.MAX_VALUE, r = Integer.MIN_VALUE;
for (int x : nums) {
l = Math.min(l, x);
r = Math.max(r, x);
}
while (l + 1 < r ) {
int mid = (l + r) / 2;
if (check(mid)) {
l = mid;
} else {
r = mid;
}
}
if (check(r)) {
return r;
}
return l;
}
private boolean check(int x) {
int count = 0;
for (int e : nums) {
if (e >= x) {
count++;
}
}
return count >= k;
}
}
```

O(nlog(max-min))

Use “Binary Indexed Tree (BIT)” (Fenwick Tree) data structure which supports querying prefix sum and adding a value to a single point.

Binary Indexed Tree is a data structure not introduced on most undergraduate and graduate algorithm classes. I would recommend a youtube here.

If you are not fully understand this data structure, don’t worry, just heed that:

- c[] array starts from index
**1**. - add(int x, int y) means add x to position y.

Then, try to memorize “add()”, “sum()” and “low_bit()” operations code, they are short! Practice more and you will be more perfect with BIT!

Back to this leetcode question, one thing to pay attention is, in the question, update(1, 2) means update the value on index 1 to 2, not add 2 to index 1. So, don’t forget to update original array as well as to update c[] arryay.

```
public void update(int i, int val) {
add(i + 1, val - nums[i]);
nums[i] = val; //don't forget this step!
}
```

```
class NumArray {
private int N;
private int c[];
private int[] nums;
public NumArray(int[] nums) {
N = nums.length;
c = new int[N + 1];
this.nums = nums;
for(int i = 1; i <= N; i++) {
add(i, nums[i-1]);
}
}
public void update(int i, int val) {
add(i + 1, val - nums[i]);
nums[i] = val; //don't forget this step!
}
public int sumRange(int i, int j) {
return sum(j+1) - sum(i);
}
private void add(int x, int y) {
while (x <= N) {
c[x] += y;
x += low_bit(x);
}
}
private int sum(int x) {
int ans = 0;
while (x > 0) {
ans += c[x];
x -= low_bit(x);
}
return ans;
}
private int low_bit(int x) {
return x & -x;
}
}
```

Runtime: 8 ms, faster than 99.88% of Java online submissions for Range Sum Query – Mutable.Memory Usage: 45.4 MB, less than 93.75% of Java online submissions for Range Sum Query – Mutable.

]]>There are several approaches to solve this problem, like sliding window or DP. A more general description of this problem is how to quickly find a **Maximum** or **Minimum** between two indices in a **fixed** array? This kind of question is called RMQ (Range Minimum Query).

Given a fixed array A and two indices i ≤ j, what is the smallest element out of A[i], A[i + 1], …, A[j – 1], A[j]?

The following content is adopted from lectures from Stanford.

```
class Solution {
int N , M ;
int[][] dp;
int[] nums;
public int[] maxSlidingWindow(int[] nums, int k) {
this.nums = nums;
N = nums.length + 1;
M = (int) (Math.log(N) / Math.log(2)) + 1;
dp = new int[N][M];
prepare();
int[] ans = new int[nums.length - k + 1];
for(int i = 0; i + k <= nums.length; i++) {
ans[i] = query(i, i + k - 1);
}
return ans;
}
private void prepare() {
for(int i = 0; i < nums.length; i++) {
dp[i][0] = nums[i];
}
for (int j = 1; j < M; j++) {
for(int i = 0; i + (1 << j) - 1 <= nums.length; i++) {
dp[i][j] = Math.max(dp[i][j-1], dp[i + (1 << (j - 1))][j-1]);
}
}
}
private int query(int l, int r) {
int k = (int) (Math.log(r - l + 1) / Math.log(2));
return Math.max(dp[l][k], dp[r - (1 << k) + 1][k]);
}
}
```

]]>