Algorithms - Week 1(2), Part I, Princeton University

Interview Questions

Social network connectivity

题目描述

Given a social network containing n members and a log file containing m timestamps at which times pairs of members formed friendships, design an algorithm to determine the earliest time at which all members are connected (i.e., every member is a friend of a friend of a friend ... of a friend). Assume that the log file is sorted by timestamp and that friendship is an equivalence relation. The running time of your algorithm should be m logn or better and use extra space proportional to n.

解答

题目提炼:n 个对象 m 条 union 记录(每次 2 个对象建立连接),找到第几次 union 后所有对象全连接。
数据结构:

  • 一个容量为 n 的数组,初始状态存储各自 index;
  • 一个容量为 n 的数组,记录树的对象数量;
  • 一个常量记录树的数量,当数量为 1 的时候全部对象互相连接;
  • 私有方法 root,获得某个对象的 root;
  • 公有方法 union,连接两个对象,修改 root,如果树的数量降低为 1 返回 true,否则为 false。
/**
  *array id stores root of each object;
  *array size stores the number of objects of each tree;
  *constant component represents the number of trees;
  *function root returns the root of the specific object;
  *function union recalculate the root of one object and the number of trees, *when the number decreases to one, it returns true, vice versa.
  */


public class SocialNetwork {
    private int[] id;
    private int[] size;
    private int component;
    
    public SocialNetwork(int n) {
        component = n;
        id = new int[n];
        for (int i = 0; i < n; i++) {
            id[i] = i;
        }
    }
    
    private int root(int i) {
        int count = 0;
        while (i != id[i]) {
            i = id[i];
            count += 1;
        }
        size[i] = count;
        return i;
    }
    
    public boolean union(int p, int q) {
        int rootP = root(p);
        int rootQ = root(q);
        if (rootP != rootQ) {
            component -= 1;
            if (component == 1) { return true; }
            if (size[p] >= size[q]) {
                id[q] = rootP;
            } else {
                id[p] = rootQ;
            }
        }
        return false;
    }
}

Union-find with specific canonical element

题目描述

Add a method () to the union-find data type so that () returns the largest element in the connected component containing i. The operations, (), (), and () should all take logarithmic time or better.
For example, if one of the connected components is {1,2,6,9}, then the () method should return 9 for each of the four elements in the connected components.

解答

在平衡树的前提下,增加一个方法 find(int p) 返回 p 所在 components 中最大的元素。
过去查找 root 的搜索是向上搜索寻找树的根,find 的不同是要双向搜索检索最大的元素。但是双向搜索无法满足 logN 的算法复杂度,所以必须在 union 的时候处理每棵树的最大值问题,增加一个 max 的数组记录每棵树的最大元素。

public class FindUF {
    private int[] id;
    private int[] size;
    private int[] max;
    
    public FindUF(int n) {
        id = new int[n];
        for (int i = 0; i < n; i++) {
            id[i] = i;
        }
    }
    
    private int root(int i) {
        int count = 0;
        int max = i;
        List candidates = new ArrayList();
        candidates.add(i);
        while (i != id[i]) {
            i = id[i];
            count += 1;
            max = i > max : i ? max;
            candidates.add(i);
        }
        size[i] = count;
        max[i] = max;
        for (candidate : candidates) {
            max[candidate] = max;
        }
        return i;
    }
    
    public void union(int p, int q) {
        int rootP = root(p);
        int rootQ = root(q);
        if (rootP != rootQ) {
            if (size[p] >= size[q]) {
                id[q] = rootP;
            } else {
                id[p] = rootQ;
            }
        }
    }
    
    public boolean connected(int p, int q) {
        return root(p) == root(q);
    }
    
    public int find(int i) {
        return max[i];
    }
}

Successor with delete

题目描述

Given a set of n integers S = { 0, 1, ... , n-1 } and a sequence of requests of the following form:

Remove x from S
Find the successor of x: the smallest y in S such that y≥x.

design a data type so that all operations (except construction) take logarithmic time or better in the worst case.

解答

输入一组整数,从中删除一个数,找到这个数后续比他大的最小的数字。
从这个数字的位置开始向后遍历,如果数字比删除数字大,则和当前最小数比较,如果比当前最小数小,则更新最小数字,直到结束,返回最小数字即可。

public class SuccessorDelete {
    private int[] sequence;
    
    public SuccessorDelete(int[] intArray) {
        sequence = intArray;
    }
    
    public int delete(int p) {
        int min;
        boolean start = false;
        for (int i = 0; i < sequence.length(); i ++) {
            if (!start && p != sequence[i]) { continue; }
            if (!start) { start = true; }
            if (start) {
                if (sequence[i] >= p) {
                    if (min == null) { min = sequence[i]; }
                    else { min = sequence[i] < min ? sequence[i] : min; }
                }
            }
        }
        return min;
    }
}

你可能感兴趣的:(Algorithms - Week 1(2), Part I, Princeton University)