3.23

字典树、拓扑排序、并查集

字典序的第K小数字

thinking

由题设,我们可以知道,第k小的数字,就是前序遍历字典树的第k个数字,

  • 1

    • 10 11 12

      • 101 102

      ……..

问题就是如何遍历此字典树:

容易得到,对于节点i来说,它的子节点有10xi+1——10xi+9。

我们用1-n对所有的节点进行标号统计

  • 假设我们查询到第i个节点,那么我们还需要查询\(k-i\)个节点,我们不妨设i的子树有\(count_i\)个节点,
  • if \(count_i\)<=\(k-i\),那么我们需要到相邻的子树上进行查询
  • if \(count_i\)>\(k-i\),那么需要的节点就是在当前的子树上,检查下一层节点。
  • 继续调用上述的步骤

那么,我们目前需要解决的就是,\(count_i\)的求解,\(left=i*10,right=i*10+9\),所以下一层有\(right-left+1\)个节点,同理,继续更新\(left,right\),其中\(right=min(right*10+9,n)\),截至条件为\(left<n\)

solution

class Solution {
public:
    int getcount(int ans,int n) {
        int count=0;
        long left=ans,right=ans;
        while(left<=n) {
            count+=min(right,(long)n)-left+1;
            left=left*10;
            right=right*10+9;
        }
        return count;
    }
    int findKthNumber(int n, int k) {
        int ans=1;
        --k;
        while(k>0) {
            int count=getcount(ans,n);
            if(count<=k) {
                k-=count;
                ++ans;
            } else {
                ans*=10;
                --k;
            }
        }
        return ans;
    }
};

奇怪的打印机 II

thinking

我们直接从题设进行考虑,让我们求解是否有一种颜色的序列,满足先后涂抹后,可以使得举行变成给定的样子——即对颜色进行拓扑排序。

图相关的题目感觉代码量就是大。

由于题目提供数据,我们首先确定各种颜色的上下左右边界的范围大小,如果说,某一种颜色在另一种颜色的范围内,那么此种颜色相当于包围它的那种颜色来说,是排在后面的,我们建立一条有向的边。最后对建成的图进行拓扑排序,查找是否出现环即可。下面即是代码实现。

solution

class Solution {
public:
    int w[61],a[61],s[61],d[61];
    bool isPrintable(vector<vector<int>>& t) {
        int m=t.size();
        int n=t[0].size();
        int k;
        memset(w,127,sizeof(w));
        memset(a,127,sizeof(a));
        memset(s,0,sizeof(s));
        memset(d,0,sizeof(d));
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j) {
                k=t[i][j];
                w[k]=min(w[k],i);
                a[k]=min(a[k],j);
                s[k]=max(s[k],i);
                d[k]=max(d[k],j);
            }
        bool vis[61][61]={0};//判断是否有边相连
        vector<vector<int>> edge(61);
        int in[61];//统计入度
        memset(in,0,sizeof(in));
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j) {
                k=t[i][j];
                for(int color=1;color<=60;++color) {
                    if(w[color]<=i&&a[color]<=j&&s[color]>=i&&d[color]>=j&&color!=k&&!vis[color][k]) {
                        edge[color].push_back(k);
                        ++in[k];
                        vis[color][k]=true;
                    }
                }
            }
        int i;
        vector<int> v;
        while(1) {
            for(i=1;i<=60;++i) {
                if(in[i]==0) {
                    v.push_back(i);
                    in[i]=-1;
                    for(int e:edge[i]) {
                        --in[e];
                    }
                    break;
                }
            }
            if(i==61) break;
        }
        return v.size()==60;
    }
};

Satisfiability of Equality Equations

thinking

并查集板子题,如果是false,必然存在某一个或者多个\(x_i=y_i\),\(x_i!=y_i\)同时存在,我们需要对等号进行合并,再非等号上查询即可。

代码如下:

solution

class UnionFind
{
public: 
	vector<int> par;
	vector<int> rank;
public:
	void init(int n)
	{
		par.reserve(n);
		rank.reserve(n);
		for(int i=0;i<n;i++)
		{
			par[i]=i;
			rank[i]=i;
		}
	}
	
	int find(int x)
	{
		if(par[x]==x) {return x;}
		else {
			return par[x]=find(par[x]);
		}
	}
	
	void unite(int x,int y)
	{
		x=find(x);
		y=find(y);
		if(x==y) return;
		if(rank[x]<rank[y]) {par[x]=y;
		} else {
			par[y]=x;
			if(rank[x]==rank[y]) rank[x]++;
		}
	}
	
	bool same(int x,int y)
	{
		return find(x)==find(y);
	}
};
class Solution {
public:
    bool equationsPossible(vector<string>& a) {
        UnionFind uf1,uf2;
        uf1.init(26),uf2.init(26);
        for(auto &&ee:a) {
            if(ee[1]=='=') {
                uf1.unite(ee[0]-'a',ee[3]-'a');
            }
        }
        for(auto &&ee:a) {
            if(ee[1]=='!') {
                if(uf1.same(ee[0]-'a',ee[3]-'a')) return false;
                uf2.unite(ee[0]-'a',ee[3]-'a');
            }
        }
        return true;
    }
};
posted @ 2022-03-24 00:08  圣道  阅读(158)  评论(0)    收藏  举报