Leetcode 1512. 好数对的数目

本文介绍了LeetCode 1512题目的解决方案,包括暴力求解和哈希表两种方法。暴力求解通过双重循环进行配对比较,而哈希表则统计每个元素出现的次数并计算好数对数量。

Leetcode 1512. 好数对的数目

题目描述

给你一个整数数组 nums 。
如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组 好数对 。
返回好数对的数目。

示例1:

输入:nums = [1,2,3,1,1,3]
输出:4
解释:有 4 组好数对,分别是 (0,3), (0,4), (3,4), (2,5) ,下标从 0 开始

示例2:

输入:nums = [1,1,1,1]
输出:6
解释:数组中的每组数字都是好数对

示例3:

输入:nums = [1,2,3]
输出:0

解题思路

暴力求解
使用两层循环求解,第一层for循环用来记录 好数对 的第一个数字nums[i],第二层for循环用来记录 好数对 的第二个数字 nums[j],如果 nums[i] == nums[j],那么 好数对 的数量就加一。这样,时间复杂度就为(O(n2n^2n2))。

class Solution {
public:
    int numIdenticalPairs(vector<int>& nums) {
        if(nums.size() <= 1){
            return 0;
        }

        int count = 0;
        for(int i=0; i<nums.size(); i++){
            for(int j=nums.size()-1; j>i; j--){
                if(nums[i] == nums[j]){
                    count++;
                }
            }
        }
        return count;
    }
};

哈希表解题

若某数字 k 在数组中出现 n 次,那么满足 nums[i] = nums[j] = k 的排列组合应该为 A(n,2),也就是 n(n-1)。但是考虑到 i < j 。那么在所有排列中,只有一半的排列满足要求,即 n(n-1)/2。时间复杂度为(O(nnn))

class Solution {
public:
    int numIdenticalPairs(vector<int>& nums) {
        unordered_map<int, int> map;
        for(int i=0; i<nums.size(); i++){
            map[nums[i]]++;
        }

        int count = 0;
        for(auto num : map){
            count += (num.second)*(num.second-1)/2;
        }

        return count;
    }
};

根据上面的思路,我们使用两个循环,先记录每个数字出现的次数,然后再计算由这个数字组成的 好数对。下面使用一个for循环完成上面的操作。

class Solution {
public:
    int numIdenticalPairs(vector<int>& nums) {
        unordered_map<int, int> map;
        int count = 0;

        for(int i=0; i<nums.size(); i++){
            if(map.find(nums[i]) != map.end()){
                count += map[nums[i]];
            }
            map[nums[i]] += 1;
        }

        return count;
    }
};

欢迎大家关注我的个人公众号,同样的也是和该博客账号一样,专注分享技术问题,我们一起学习进步
在这里插入图片描述

<think>好的,用户需要的是用C++实现LeetCode1254题,而且要求不使用类。首先,我得先理解题目要求。题目是统计封闭岛屿的数目,封闭岛屿指的是完全被水域包围的陆地,也就是说,岛屿不能位于矩阵的边缘,否则就可能接触到边界而无法被水域包围。接下来,我需要参考用户提供的引用内容。用户引用了几个不同的解决方案,包括Java和C++的代码,其中有的使用类,有的用DFS或BFS。用户特别提到要C++实现且不用类,所以需要将类的方法转换为函形式。首先看引用中的C++代码,比如引用[2]中的Solution类,里面有closedIsland方法和dfs方法。为了不使用类,可以将这些成员函改为全局函或者静态函,或者直接在main函外定义。不过通常,在C++中,可以将函放在全局作用域,或者使用命名空间,但用户可能只需要一个函式的实现,不需要类的封装。然后,分析算法思路。封闭岛屿的条件是岛屿的所有陆地都不在矩阵的边界上。因此,遍历矩阵中的每个点,当遇到陆地(0)时,进行DFS或BFS遍历,将相连的陆地标记为已访问,同时检查是否触及边界。如果整个岛屿都没有触及边界,则计加一。需要注意的点是,如何标记已访问的陆地。通常的做法是修改原矩阵,将访问过的陆地标记为1(水)或者其他值,比如2,避免重复访问。这样在遍历时就不会重复处理同一块陆地。 接下来,考虑如何将类的方法转换为独立函。例如,引用[2]中的closedIsland函作为类的成员函,可以改为一个全局函,接受grid的引用作为参,并返回整结果。同样,dfs函也需要调整,可能通过传递引用来修改grid和判断是否触及边界。 然后,处理边界条件。在DFS过程中,如果发现当前坐标在矩阵的边界上(i==0或 i== rows-1或j ==0或j ==cols-1),则这个岛屿不是封闭的,需要标记为无效。例如,在引用[2]中,使用一个val变量,初始为1,如果遇到边界,则设置为0。这样在遍历完整个岛屿后,如果val仍为1,则计增加。 现在,将这些思路整合成一个不使用类的C++实现。具体步骤如下: 1.编写一个DFS函,参包括grid的引用,当前坐标i,j,以及一个引用变量is_closed(或者指针)来记录是否触及边界。2.在DFS过程中,检查当前坐标是否在边界,如果是,则将is_closed设为false。 3.遍历四个方向,递归处理相邻的陆地。 4.主函中遍历整个矩阵,对每个未访问的陆地(值为0)启动DFS,并根据is_closed的值决定是否计。需要注意的是,修改grid来标记已访问的陆地,比如将0改为1或其他值。同时,要正确处理矩阵的行列,避免越界访问。现在,编写代码的大纲:-函closedIsland接受二维vector的引用,返回整。 -DFS辅助函,参包括i,j, grid的引用,以及一个bool引用或指针来标记是否封闭。 -遍历每个点,如果是陆地,则调用DFS,并统计结果。检查引用中的例子,比如引用[3]中的代码,他们使用了一个flag组来标记是否访问过,但用户可能需要更节省空间的方法,直接修改原grid。例如,将访问过的陆地标记为1,这样就不需要额外的存储空间。例如,在引用[2]的代码中,DFS函里将访问过的陆地标记为1,这样在后续遍历中就不会重复处理。所以,在编写代码时,可以在DFS中将grid[i][j]=1,以避免重复访问。然后,处理封闭判断。例如,在DFS开始时,假设该岛屿是封闭的(is_closed= true),如果在DFS过程中发现任何边界点,则将is_closed设为false。最后,如果is_closed为true,则计加一。现在,将这些转化为代码:主函遍历每个单元格,当遇到0时,调用DFS,并传递一个变量来记录是否封闭。例如: intclosedIsland(vector<vector<int>>& grid) {introws= grid.size();if(rows==0)return0;intcols =grid[0].size();intcount =0;for(inti =0;i <rows;++i) {for(intj =0;j <cols;++j) {if(grid[i][j]==0){bool is_closed= true;dfs(grid, i, j, is_closed);if (is_closed){++count;}}}}return count; }然后,DFS函的实现:void dfs(vector<vector<int>>&grid,int i, intj,bool&is_closed){int rows= grid.size();intcols =grid[0].size();//检查是否在边界if(i==0 ||i ==rows-1 ||j ==0|| j== cols-1) {is_closed= false;//这里不能直接返回,因为还要继续标记所有相连的陆地}//标记为已访问grid[i][j] =1;//四个方向vector<pair<int,int>>dirs= {{-1,0}, {1,0},{0,-1}, {0,1}};for (auto dir: dirs){int x= i+ dir.first;inty =j +dir.second;if (x >=0&& x< rows&& y>=0&& y< cols&& grid[x][y]==0){dfs(grid, x, y, is_closed);}} }这样,每次DFS遍历一个岛屿,并在过程中检查是否有边界点,从而判断是否封闭。需要注意的是,即使某个点位于边界,仍然需要继续遍历整个岛屿,以确保所有相连的陆地都被标记为已访问,避免重复处理。因此,在DFS中,即使发现边界点,也需要继续处理相邻的节点,而不是立即返回。 现在,测试这个代码是否正确。例如,引用[4]中的示例输入,输出应该是2。用这个代码处理的话,应该正确统计封闭岛屿的量。另外,需要考虑矩阵为空的情况,所以在主函中先检查rows是否为0,避免越界错误。 这样,代码应该可以正确运行,并且没有使用类,符合用户的需求。</think>### LeetCode 1254 C++ 实现(不使用类) **问题分析** 封闭岛屿的定义是:被水域完全包围的陆地区域,即岛屿的所有陆地格子均不位于矩阵边界上。因此,解题思路为: 1. 遍历所有格子,遇到陆地(0)时启动深度优先搜索(DFS) 2. 在DFS过程中标记已访问的陆地,并检查是否触及矩阵边界 3. 若整个岛屿未触及边界,则计加一 **C++代码实现** ```cpp #include <vector> using namespace std; void dfs(vector<vector<int>>& grid, int i, int j, bool& is_closed) { int rows = grid.size(); int cols = grid[0].size(); // 检查当前点是否在边界 if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) { is_closed = false; // 标记为非封闭岛屿 } // 标记当前点为已访问(改为水域) grid[i][j] = 1; // 定义四个方向 int dx[] = {-1, 1, 0, 0}; int dy[] = {0, 0, -1, 1}; // 遍历相邻格子 for (int k = 0; k < 4; ++k) { int x = i + dx[k]; int y = j + dy[k]; if (x >= 0 && x < rows && y >= 0 && y < cols && grid[x][y] == 0) { dfs(grid, x, y, is_closed); } } } int closedIsland(vector<vector<int>>& grid) { if (grid.empty()) return 0; int rows = grid.size(); int cols = grid[0].size(); int count = 0; for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { if (grid[i][j] == 0) { bool is_closed = true; dfs(grid, i, j, is_closed); if (is_closed) { ++count; } } } } return count; } ``` **代码说明** 1. **DFS函**:通过递归标记相连的陆地,并检查是否接触边界。参 `is_closed` 作为引用传递,用于记录岛屿的封闭状态[^2] 2. **主函**:遍历矩阵,对每个未访问的陆地启动DFS,并根据 `is_closed` 统计封闭岛屿量 3. **边界处理**:DFS过程中若发现陆地接触矩阵边界,则标记该岛屿为非封闭[^4] **复杂度分析** - 时间复杂度:$O(mn)$,每个格子最多访问一次 - 空间复杂度:$O(mn)$,递归栈深度最坏情况下为矩阵大小
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值