算法1

先用一个用烂了的面试题, 给脑子热个身。

【 问题-1】:

给一个单链表,请用最快的方法判断单链表是否有环?环的长度是多少?环的接入点是哪个?

【 分析】:

O(n)完全跑一遍一定不够快。

判断是否有环可以使用追赶法。用两个指针,一个快(fast)一个慢(slow),fast指针一次走两步,slow指针一次走一步。如果fast遇到null则不存在环, 如果fast遇到slow就说明存在环。

如果你这样解决这个问题, 面试官一定会问你为什么。因为很多人都知道这样做,但未必真的理解为什么。

如果有环, 两个指针一定是快指针先进入环, 然后慢指针进入环。

接下来我们认为快指针在环中追赶慢指针,因为步数差1,所以二者距离每次减小1,直至追到。

下面来论证需要多少次能追上,

假设二者最初相距m的距离,则需要m次,因为距离每次减小1嘛,也就是最多需要慢指针走完一次环的长度。所以最慢的情况是走完一遍,也就是O(n)的复杂度内可以解决是否有环的问题。

(不好画图,脑补一下)

然后来计算环到底有多长。

用之前的想法来继续想一下,只要让他们继续走,等到再次遇到的时候又走的次数就是环的长度了。

因为当二者相遇,我们可以认为他们的距离是0也可以认为是环的长度,所以只要再次相遇,中间的步数就是环的长度。

环的入口点是哪个:

设环长m, 设相遇的时候,slow走了s步, fast就走了2s步。则2s = km + s。 也就是fast指针走的路程的另外一种表示:在圈内转的圈数k,加slow走的路程。

同时,我们设起点到入口距离为k1, 入口距离相遇点k2, 相遇点距离入口k3。(注意环上的距离,是有方向的),

得到:

s = k1+ k2;

k1 = (k-1)m + k3;

所以起点到入口的距离==相遇点开始转(k-1)圈后再到入口的距离。所以只要从起点和相遇点同时出发,相遇的时候就是入口点。

(看了几个网上的说法,有很多是错的。TVT)

【 问题-2】:

给一个无向图,问这附图是否是一个树。

【 分析】:

首先要明白树的定义。

一个有n个节点,且有n-1条边的联通图是树。

首先要仅有n-1条边,其次要是一个联通图,也就是任意两个点可以互相抵达。

不满足n-1条边的我们可以直接判断掉。

接下来有两种做法。

并查集方法:

并查集是一种数据结构,应该没有封装好的工具,需要自己手动写。

这种数据结构支持两个集合的合并,查询每个元素所属的集合。不懂的可以看代码。

做法是:初始化每个点都属于单独的一个集合,然后取一条边,如果边的两个端点不在一个集合中,就合并这两个集合,如果在一个集合中就说明图中有环,就不是树。

数据:

5 [[0,1],[0,2],[0,3],[1,4]] // 5个点,4条边
代码:

class Solution {
public:
/*
* @param n: An integer
* @param edges: a list of undirected edges
* @return: true if it’s a valid tree, or false
*/
int fa[1000005]; // 并查集,记录每个点所属的集合。

int Find(int x) {
    return fa[x] = x == fa[x] ? x : Find(fa[x]);
}   // 带压缩路径的并查集

bool validTree(int n, vector<vector<int>> &edges) {
    // write your code here
    int len = edges.size();
    if(len != n - 1 || n == 0) {
        return false;
    }

    for(int i = 0; i < n; i++) {
        fa[i] = i;
    }
    for(int i = 0; i < len; i ++) {
        int fv = Find(edges[i][0]);
        int fu = Find(edges[i][1]);
        if(fv == fu){
            return false;
        } else {
            fa[fv] = fu;    // 合并两个集合
        }
    }
    return true;
}

};

BFS方法:

将边存成图,然后BFS一个联通块,看这个图是否联通。联通就是树,否则就不是

class Solution {
public:
/*
* @param n: An integer
* @param edges: a list of undirected edges
* @return: true if it’s a valid tree, or false
*/
int vis[100005];
vector Grp[100005];
bool validTree(int n, vector

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值