LeetCode 1512. 好数对的数目 Java

该博客讨论了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

提示:

1 <= nums.length <= 100
1 <= nums[i] <= 100

个人思路+代码

双循环
通过设置循环起始位置使 i<j一直成立 之后记录相等次数即可
(但是显然不会是最优解法)

class Solution {
    public int numIdenticalPairs(int[] nums) {
        int res = 0;
        for(int i=0; i<nums.length-1;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]==nums[j]){	
                    res++;		//已经满足i<j 
                }
            }
        }
        return res;
    }
}

结果:
在这里插入图片描述

双百解法:

思路(个人加的):
建立大小100的哈希数组
直接遍历,如果有相同的,直接在对应位置+1
把结果加上对应的数字
像例子中是 0+1+2+3
就是正常的结果

class Solution {
    public int numIdenticalPairs(int[] nums) {
        int ans = 0;
        //因为 1<= nums[i] <= 100  所以申请大小为100的数组
        //temp用来记录num的个数
        int[] temp = new int[100];
        /*
        从前面开始遍历nums
        假设nums = [1,1,1,1]
        第一遍
        temp是[0,0,0,0]
        ans+=0;
        temp[0]++;
        第二遍
        temp是[1,0,0,0]
        ans+=1;
        temp[0]++;
        第三遍
        temp=[2,0,0,0]
        ans+=2;
        temp[0]++;
        第四遍
        temp=[3,0,0,0]
        ans+=3;
        temp[0]++;
        */
        for (int num : nums) {
            /*
            这行代码可以写成
            ans+=temp[num - 1];
            temp[num - 1]++;
            */
            ans += temp[num - 1]++;
        }
        return ans;
    }
}

作者:JayceonDu
链接:https://leetcode-cn.com/problems/number-of-good-pairs/solution/zhe-gu-ji-shi-wo-xie-zen-yao-duo-ti-yi-lai-zui-dua/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
<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、付费专栏及课程。

余额充值