3.15力扣刷题记录

1.省份数量(并查集)

题目描述
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
难度:中等
数据范围

  • 1 <= n <= 200
  • n == isConnected.length
  • n == isConnected[i].length
  • isConnected[i][j] 为 1 或 0
  • isConnected[i][i] == 1
  • isConnected[i][j] == isConnected[j][i]

题目地址
题解
先放上临时写的并查集,距离上次写并查集已经有段时间了,代码不是很简洁,也没有打磨,但通过测试用例够用了。

class DJset{
int *parent;
int count;
public:
    DJset(int n){
        parent=new int[n];
        for(int i=0;i<n;i++)
            parent[i]=i;
        count=n;
    }
    int Find(int m){
        if(parent[m]==m)
            return m;
        else
            return Find(parent[m]);
    }
    void Union(int x,int y){
        int px=Find(x),py=Find(y);
        if(px!=py){
            parent[py]=px;
            count--;
        }
    }
    int Num(){
        return count;
    }
};
class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n=isConnected.size();
        DJset s(n);
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(isConnected[i][j]==1)
                    s.Union(i,j);
            }
        }
        return s.Num();
    }
};

再贴上按秩合并的并查集代码。

class DJset {
private:
	int* parent;//父指针数组
	int* rank;
	int count;
public:
	DJset(int N) {
		parent = new int[N];
		rank = new int[N];
		for (int i = 0; i < N; i++) {
			parent[i] = i;
			rank[i] = 1;
		}
		count = N;
	}
	int find(int x) {
		if (parent[x] == x)
			return x;
		else
			return find(parent[x]);
	}
	void merge(int i, int j) {
		int x = find(i), y = find(j);
		if (x == y)
			return;
		if (rank[x] <= rank[y])
			parent[x] = y;
		else
			parent[y] = x;
		if (rank[x] == rank[y] && x != y)
			rank[y]++;//如果深度相同且根节点不同,则新的根节点的深度+1
		count--;
	}//按秩合并
	int print_count() {
		return count;
	}
};

路径压缩的find函数

int find(int x) {
		if (parent[x] != x)
			parent[x] = find(parent[x]);//路径压缩
		return parent[x];
	}

部分代码来自https://zhuanlan.zhihu.com/p/93647900/,回顾按秩合并和路径压缩也可参考这篇文章。

2.统计子岛屿(DFS)

今天做了好几道图的深搜(广搜)题,思想都是一样的,贴一道DFS上来。
BFS要用到队列,有机会再练吧。
题目描述
给你两个 m x n 的二进制矩阵 grid1 和 grid2 ,它们只包含 0 (表示水域)和 1 (表示陆地)。一个 岛屿 是由 四个方向 (水平或者竖直)上相邻的 1 组成的区域。任何矩阵以外的区域都视为水域。
如果 grid2 的一个岛屿,被 grid1 的一个岛屿 完全 包含,也就是说 grid2 中该岛屿的每一个格子都被 grid1 中同一个岛屿完全包含,那么我们称 grid2 中的这个岛屿为 子岛屿 。
请你返回 grid2 中 子岛屿 的 数目 。
难度:中等
题目地址
题解

class Solution {
    int dirs[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
    int m,n;
    bool r;
public:
    int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
        int ans=0;
        m=grid1.size(),n=grid1[0].size();
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(grid2[i][j]==1){
                    r=true;
                    dfs(grid1,grid2,i,j);
                    if(r)
                        ans++;
                }
            }
        }
        return ans;
    }
    void dfs(vector<vector<int>>& grid1,vector<vector<int>>& grid2,int x, int y){
        if(x<0||y<0||x>=m||y>=n||grid2[x][y]!=1){
            return;
        }
        grid2[x][y]=2;
        if(grid1[x][y]!=1)
            r=false; 
        for(auto dir:dirs){
            dfs(grid1,grid2,x+dir[0],y+dir[1]);
        }
    }
};

3.每日一题:统计按位或能得到最大值的子集数目(DFS)

题目描述
给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。
如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,则认为数组 a 是数组 b 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同 。
对数组 a 执行 按位或 ,结果等于 a[0] OR a[1] OR … OR a[a.length - 1](下标从 0 开始)。
难度:中等
数据范围

  • 1 <= nums.length <= 16
  • 1 <= nums[i] <= 105

题目地址
题解
排列问题,时间复杂度O( 2 n 2^n 2n)。
1. 代码来自官方题解。添加一些注释。

class Solution {
public:
    int countMaxOrSubsets(vector<int>& nums) {
        this->nums = nums;
        this->maxOr = 0;//能得到的按位或的最大的值,就是将nums中所有的数按位或得到的数。
        this->cnt = 0;
        dfs(0, 0);
        return cnt;
    }

    void dfs(int pos, int orVal) {//orVal是当前按位或得到的数
        if (pos == nums.size()) {//dfs终结条件,遍历到末尾
            if (orVal > maxOr) {
                maxOr = orVal;//每次维护新的最大值
                cnt = 1;
            } else if (orVal == maxOr) {
                cnt++;
            }
            return;
        }
        dfs(pos + 1, orVal| nums[pos]);//选择num[pos]
        dfs(pos + 1, orVal);//不选num[pos]
    }

private:
    vector<int> nums;
    int maxOr, cnt;
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/solution/tong-ji-an-wei-huo-neng-de-dao-zui-da-zh-r6zd/

2. 提前算出maxVal,每次比较curVal和maxVal的大小,不用动态更新。

class Solution {
vector<int> nums;
public:
    int countMaxOrSubsets(vector<int>& nums) {
        this->nums=nums;
        int maxVal=0;
        for(auto a:nums)
            maxVal|=a;
        return dfs(0,0,maxVal);
    }
    int dfs(int curIndex, int curValue, int maxVal){
        if(curIndex==nums.size()){
            return maxVal==curValue?1:0;
        }
        return dfs(curIndex+1,curValue|nums[curIndex],maxVal)+dfs(curIndex+1,curValue,maxVal);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值