Interview Questions: Union–Find (ungraded)

最近在学coursera上的算法课程。下面是课后习题的答案。

1.

Social network connectivity. Given a social network containing nn members and a log file containing mm 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 \log nmlogn or better and use extra space proportional to nn.

Note: these interview questions are ungraded and purely for your own enrichment. To get a hint, submit a solution.

这题比较基础,有一个log file里面保存的数据是 时间  p  q,意思是在某个时刻p与q产生了联系,题目问在什么时候,所有人都产生了联系,即联通分量为1。

package sec1.Exercise;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Sec1Exercise {
    private int[] id;
    private int[] sz;
    private int count;
    FileInputStream ins;

    public Sec1Exercise(int N,FileInputStream ins){
        this.ins = ins;
        id = new int[N];
        sz = new int[N];
        count = N;
        for(int i = 0;i < N;i++){
            id[i] = i;
        }
        for(int i = 0;i < N;i++){
            sz[i] = 1;
        }


    }

    public String getEarlyTime(){
        Scanner scanner = new Scanner(ins,"utf-8");
        String time = null;
        while(scanner.hasNextLine()){
            String line = scanner.nextLine();
            if(line != null&&!line.trim().equals("")){
                String[] lineArray = line.split(" ");
                Integer p = Integer.parseInt(lineArray[1]);
                Integer q = Integer.parseInt(lineArray[2]);
                union(p,q);
                if (count == 1){
                    return lineArray[0];
                }
            }
        }
        return "";
    }

    public int find(int i){
        while(id[i] != i){
            i = id[i];
        }
        return i;
    }

    public void union(int i,int j){
        int pId = find(i);
        int qId = find(j);
        if(pId == qId){
            return;
        }
        if(sz[i] < sz[j]){
            sz[j] += sz[i];
            id[i] = j;
        }else{
            sz[i] += sz[j];
            id[j] = i;
        }
        count--;
    }

    public static void main(String[] args) {
        FileInputStream ins;
        try {
            ins = new FileInputStream("socialNetworkLog.txt");
            Sec1Exercise sec1Exercise = new Sec1Exercise(10,ins);
            System.out.println(sec1Exercise.getEarlyTime());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}


//socialNetworkLog.txt
//20170714001 0 1
//20170714002 4 5
//20170714003 8 9
//20170714004 2 4
//20170714005 5 6
//20170714006 7 8
//20170714007 2 5
//20170714008 6 7
//20170714009 1 2
//20170714010 0 3
//20170714011 1 9
//20170714012 3 7

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 ii. The operations, ?????(), ?????????(), and ????() should all take logarithmic time or better.

For example, if one of the connected components is \{1, 2, 6, 9\}{1,2,6,9}, then the ????() method should return 99 for each of the four elements in the connected components.

这个题目的意思是求出每个联通分量中的最大值,若用quick-find法,则非常简单,每个联通分量的根节点即为最大值。若采用weighted-quick-union则需要维护一个max数组,每个联通分量的根节点保存最大值。

package sec1.Exercise;

public class UF {

    private int[] id;   //分量id
    private int[] sz;   //各个根节点所对应的分量的大小
    private int count;  //分量数量
    private int[] max;

    public UF(int N){
        count = N;
        id = new int[N];
        sz = new int[N];
        max = new int[N];
        for(int i = 0;i < N;i++){
            id[i] = i;
            sz[i] = 1;
            max[i] = i;
        }

    }

    public int count(){
        return count;
    }

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

    private int find(int i){
        while (id[i] != i){
            i = id[i];
        }
        return i;
    }

    public void union(int p,int q){
        int pId = find(p);
        int qId = find(q);

        if(pId == qId){
            return;
        }
        if(sz[pId] < sz[qId]){
            id[pId] = qId;
            sz[qId] += sz[pId];
            max[qId] = max[pId] > max[pId] ? max[pId] : max[qId];
        }else{
            id[qId] = pId;
            sz[pId] += sz[qId];
            max[pId] = max[pId] > max[qId] ? max[pId] : max [qId];
        }
        count--;
    }

    public int getMax(int i){
        return max[find(i)];
    }

}

3. 

Successor with delete. Given a set of nn integers S = \{ 0, 1, ... , n-1 \}S={0,1,...,n−1} and a sequence of requests of the following form:

  • Remove xx from SS
  • Find the successor of xx: the smallest yy in SS such that y \ge xy≥x.

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

这个题目的意思是,有一段从0开始的连续序列,每次都会从序列中取出一个数x,求序列中比x大,但最小的那个数。

package sec1.Exercise;

public class Successor {

    private int N;
    private int[] num;
    private boolean[] isRemove;

    public Successor(int N){
        num = new int[N];
        for(int i = 0;i < N;i++){
            num[i] = i;
            isRemove[i] = false;
        }
    }

    public int find(int i){
        while(i != num[i]){
            i = num[i];
        }
        return i;
    }

    public void remove(int index){
        if(index - 1 >= 0&&isRemove[index - 1]){
            union(index,index - 1);
        }else if(index + 1 < N&&isRemove[index + 1]){
            union(index,index + 1);
        }
    }

    public void union(int p,int q){
        int i = find(p);
        int j = find(q);
        if(i == j){
            return;
        }
        if(i < j){
            num[i] = j;
        }else {
            num[j] = i;
        }
    }

    public int getSuccessor(int x){
        int num = find(x) + 1;
        if(num < N){
            return num;
        }
        return -1;
    }

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值