2022 春 字节题(六)


大数相加

class Solution3
{
public:
	string solve3(string s, string t)
	{
		if (s.size() == 0)return t;
		if (t.size() == 0)return s;
		int m = max(s.size(), t.size())+1;//取 s t中较长的字符串做被加数
		int len_s = s.size() - 1;
		int len_t = t.size() - 1;
		int carry = 0;//进位标志
		int cur=0;//余数标志
		string ans(m, '0');//初始化一个字符串保存相加的结果
		for (int i = m-1; i >= 0; i--)//倒叙遍历那个较长的数字
		{
			int x = len_s >= 0 ? s[len_s] - '0' : 0;//字符串转整数
			int y = len_t >= 0 ? t[len_t] - '0' : 0;
			int sum = x + y + carry;
			carry = sum / 10;//进位
			cur =sum% 10;//余数
			ans[i] = cur + '0';//保存相应位上的和 整数转字符串
			--len_s;//继续进行下一位的相加
			--len_t;
		}
		if (ans[0] == '0')return ans.substr(1);//结果字符串相加之后的第一位是0  / 从下标为1的位置开始截取 一共截取到末尾
		return ans;
	}
};

【二叉树的直径】

给定一颗二叉树,计算其直径长度;
一颗二叉树的直径长度是是任意两个节点路径长度的最大值,这条路径可能穿过也可能不穿过根节点。



class Solution
{
public:
	int res = 0;//全局变量 两个函数里共享这个变量
	int diameterOfBinaryTree(TreeNode* root)
	{
		maxPath(root);
		return res;
	}
	int  maxPath(TreeNode* root)
	{
		//递归终止条件是到达叶子节点
		if (!root->left && !root->right)return 0;//这里的递归终止条件不是 !root 因为单个节点的路径长也是0
		int left = root->left ? maxPath(root->left) + 1 : 0;//每进行一次递归 路径长度就加一(left right既可以理解为长度 也可以理解为深度)
		int right = root->right ? maxPath(root->right) + 1 : 0;
		res = max(res, left + right);//更新全局变量
		return max(left, right);//左右路径中的较大者作为向上一层的返回值
	}
};


剑指2 最长递增路径H

给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。
在这里插入图片描述
在这里插入图片描述



//最长递增路径-----记忆化DFS解法
//当前点的最大长度=max(上,下,左,右)的长度;
class Solution {
public:
	int m, n;
	int maxLen = 0;//返回最长路径的长度
	int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };//维护一个四行两列的二维数组 分别表示从当前位置移动到上下左右四个位置坐标的增减情况
	bool bound(int x, int y) {
		if (x < 0 || x >= m || y < 0 || y >= n) return false; //单独写一块bool 代码来控制边界
		return true;
	}
	int dfs(int x, int y, vector<vector<int>>& dp, vector<vector<int>>& matrix) {
		if (dp[x][y]) return dp[x][y]; //递归终止条件----如果当前访问过的节点之前计算过最长的递增长度就直接返回结果;
		int len = 1;//初始化最长递增路径长度为1 至少有一个节点
		for (int i = 0; i < 4; ++i) {
			int nx = x + dir[i][0], ny = y + dir[i][1];//nx ny表示下一个位置的 x y坐标
			if (bound(nx, ny) && matrix[nx][ny] > matrix[x][y]) len = max(len, dfs(nx, ny, dp, matrix) + 1);//在这里实现最长递增路径的加一
		}
		dp[x][y] = len;//给出以 (x,y)为起点的最长递增路径的长度;
		return len;
	}
	int longestIncreasingPath(vector<vector<int>>& matrix) {
		m = matrix.size(); n = matrix[0].size();
		vector<vector<int>> dp(m, vector<int>(n));//dp[i][j]表示以(i,j)为路径起点的最长递增路径的长度;
		for (int i = 0; i < m; ++i) {
			for (int j = 0; j < n; ++j) {
				dp[i][j] = dfs(i, j, dp, matrix);//以当前位置为起点进行深度搜索
				maxLen = max(maxLen, dp[i][j]);//每一次的搜索都会计算一个递增路径的长度,这里需要维护一个最长的递增路径;
			}
		}
		return maxLen;
	}
};


求1+2+…n

剑指36 二叉搜索树转双向链表

在这里插入图片描述

class Solution
{
public:
	Node* pre = nullptr, * head = nullptr;//pre指针用于遍历树中的每一个节点;head指针用于记录排序链表的头节点 始终指向的都是同一个节点
	Node* treeToDoubleyList(Node* root)
	{
		if (!root)return root;
		dfs(root);
		head->left = pre;//首尾相连 将双向链表转成循环链表
		pre->right = head;
		return head;
	}
	void dfs(Node* root)
	{
		//中序遍历的遍历顺序就是双向链表的建立顺序 我们要做的是在中序遍历的过程中 修改每个节点的左右指针 将零散的节点连接成双向循环链表
		if (!root)return;//递归终止条件
		dfs(root->left);//递归左子树到底 开始返回最左侧的节点
		if (pre)pre->right = root;//修改从pre到root的单向指针
		else head = root;//pre为空时 root就是头节点,保存链表头节点
		root->left = pre;//修改从root到pre的单向指针;此时就构造好了pre到root之间的双向指针
		pre = root;//更新 继续向下遍历 pre不断后移 来指向每一个遍历到的节点
		dfs(root->right);
	}
};


leetcode357 各个位置都不同的数字个数

在这里插入图片描述

class Solution {
public:
    int countNumbersWithUniqueDigits(int n) {
        if (n == 0)return 1;
		if (n == 1)return 10;
		int ans = 10, cur = 9;//ans初始化为10 当n大于1时 ans至少为10
		for (int i = 0; i < n - 1; i++)
		{
			cur *= 9 - i;
			ans += cur;
		}
		return ans;
    }
};


最大连续1的个数


//返回数组中连续1的个数
class Solution
{
public:
	int findMaxConsecutiveOnes(vector<int>& nums)
	{
		int n = nums.size();
		int res = 0;
		for (int i = 0; i < n; i++)//双指针的思想---- i是慢指针  j是快指针
		{
			int j = i;
			while (j < n && nums[j] == 1)j++;
			res = max(res, j - i);//当遇到连续的1时 开始计算连续1的个数 
		}
		return res;
	}
};


int main()
{
	Solution so;
	vector<int>nums = { 1,2,1,5,1,54,55,1,1,1,1,1,1,8,7,4,5,5 };
	int ans;
	ans = so.findMaxConsecutiveOnes(nums);
	cout << "最长连续1的个数为:" << ans << endl;
	system("pause");
	return 0;
}

面试题 01.06 字符串压缩

示例:
输入:"aabcccccaaa"
输出:"a2b1c5a3"

在这里插入图片描述


class Solution
{
public:
	string compressString(string S)
	{
		int i = 0;//双指针
		int j = 0;
		int l = S.length();
		string res;//返回最终的结果
		while (i < l)
		{
			while (j < l && S[i] == S[j])//当遍历的一直是相同的元素,当遍历到的是不一样的元素时,j不再向前移动,开始进行计算 添加元素和其出现的次数
			{
				j++;//j指针一直前移
			}
			res += S[i];//添加相应的元素 
			res += to_string(j - i);//添加该元素出现的次数; j移动的位数就是一个元素出现的次数
			i=j;//更新i下标,下一次计算的i的起始下标就是上一次的j的下标位置
		}
		return res;
		//return res.length() < l?res:S;
	}
};
int main()
{
	Solution so;
	string res;
	string s = "aaasdfasdfasdffffeweeeeee";
	res = so.compressString(s);
	cout << "压缩之后的字符串是:" << res << endl;
	system("pause");
	return 0;
}

leetcode 15 三数之和

找到数组中和为0的三个元素,这个三元组不能是重复的;


//寻找数组中和为0的三个数字
class Solution
{
public:
	vector<vector<int>>threeSum(vector<int>& nums)
	{
		int n = nums.size();
		if (n < 3)return {};
		vector<vector<int>>res;//可能含有多个三元组 所以用一个二维数组来接收
		sort(nums.begin(), nums.end());
		for (int i = 0; i < n; i++)
		{
			if (nums[i] > 0)return res;//排序之后最小的元素是大于的 肯定找不到和为0的三个数字
			if (i > 0 && nums[i] == nums[i - 1])continue;//对第一个数字去重 对于已经选取过的数字直接跳过;nums[i]是第一个数字
			int l = i + 1;//第二个数字
			int r = n - 1;//第三个数字
			while (l < r)
			{
				if (nums[l] + nums[r] > -nums[i])r--;//和大了 要减小和
				else if (nums[l] + nums[r] < -nums[i])l++;//和小了 要增大和
				else//找到合适的三个数字
				{
					res.push_back(vector<int>{nums[i], nums[l], nums[r]});//要找的三个数字分别是 nums[i] nums[l] nums[r]
					l++;//增大左边界 缩小搜索范围
					r--;//减小右边界
					while (l < r && nums[l] == nums[l - 1])l++;//第二个数字去重 比如:[-4,1,1,1,2,3,3,3] i=0 left=1 right=5
					while (l < r && nums[r] == nums[r + 1])r--;//第三个数字去重
				}
			}
		}
		return res;
	}
};


leetcode 322 零钱兑换 &&剑指II — 最少的硬币数目

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。

示例:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1

dp数组的含义 :当目标金额为i时,最少需要dp[i]枚硬币凑出目标金额
coins是可选硬币面值;amount是目标金额
因为凑成目标金额所需最多硬币数量为amount(此时全用一元硬币)故将其初始化为amount+1 ,初始化为一个足够大的数,防止溢出
i 表示小于amount的某个目标金额,coin表示我们枚举的最后一枚硬币的面值
dp[i]需要从dp[i-coin]这个状态转移而来;

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        vector<int>dp(amount+1,amount+1);//
        dp[0]=0;
        for(int i=1;i<=amount;++i)//遍历总金额 
        {
            for(int coin:coins)//遍历硬币
            {
                if(i-coin<0)continue;//凑成的目标金额小于给定硬币数值
                dp[i]=min(dp[i],1+dp[i-coin]);
            }
        }
        return dp[amount]>amount?-1:dp[amount];//所需硬币数量最多是amount 最后返回的结果不可能比amount大

    }
};


leetcode 1171 从链表中删除总和为0的连续节点

题目要求:
给你一个链表的头节点 head, 请你编写代码, 反复删去链表中由 总和 值为 0 的连续节点组成的序列 , 直到不存在这样的序列为止。
删除完毕后,请你返回最终结果链表的头节点。
例如:
输入:head = [1,2,3,-3,-2]
输出:[1]

在这里插入图片描述

class Solution
{
public:
	ListNode* removeZeroSumSublists(ListNode* head)
	{
		unordered_map<int, ListNode*>mp;//哈希表记录前缀和和对应的节点
		ListNode* dummyHead = new ListNode(0);//伪头
		dummyHead->next = head;
		ListNode* p = dummyHead;//创建一个指针用来遍历节点
		int sum = 0;//存储临时的前缀和
		while(p)
		{
			sum += p->val;//计算每个位置的前缀和 第一次求前缀和是为了在哈希表中进行存储
			mp[sum] = p;//在哈希表中存储前缀和及其对应的节点
			p = p->next;//继续向下遍历
		}
		for (p = dummyHead, sum = 0; p != NULL; p = p->next)
		{
			sum += p->val;//第二次遍历求和是为了寻找重复的前缀和 从而进行删除操作
			if (mp.find(sum) != mp.end())
			{
			//此时如果p和mp[sum]指向的节点是同一个节点的话 操作是没有意义的 继续寻找下一个
				p->next = mp[sum]->next;//对于当前节点前缀和 如果在哈希表中查找到有相同的就删除之间的所有节点
				//删除的就是p指向的节点和mp[sum]节点之间的所有节点 就达到了目的
			}
		}
		return dummyHead->next;
	}
};

leetcode 207 课程表 I

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。

例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。


//拓扑排序
class Solution
{
private:
	vector<vector<int>>edges;
	vector<int>visited;
	bool valid = true;
public:
	void dfs(int u)
	{
		visited[u] = 1;
		for (int v : edges[u])
		{
			if (visited[v] == 0)
			{
				dfs(v);
				if (!valid)return;
			}
			else if (visited[v] == 1)
			{
				valid = false;
				return;
			}
		}
		visited[u] = 2;
	}
	bool canFinish(int numCourses, vector<vector<int>>& prerequisites)
	{
		edges.resize(numCourses);
		visited.resize(numCourses);
		for (const auto& info : prerequisites)
		{
			edges[info[1]].push_back(info[0]);
		}
		for (int i = 0; i < numCourses && valid; i++)
		{
			if (!visited[i])dfs(i);
		}
		return valid;
	}

};

leetcode 210 课程表 II

现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1
给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi

例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。

返回你为了学完所有课程所安排的学习顺序
可能会有多个正确的顺序,你只要返回 任意一种 就可以了。
如果不可能完成所有课程,返回 一个空数组 。
例如:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:[0,1]
解释:总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1]

输入:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
输出:[0,2,1,3]
解释:总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3] 。


leetcode 84 柱状图中的最大矩阵H

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
在这里插入图片描述


//枚举的方法--宽表示矩形贴着柱状图底边的宽度 高表示矩形在柱状图上的高度;
// 暴力寻找的方法 计算每一个可能组成的矩形的面积 找最大值;
//方法一 枚举宽(超时
//使用两层循环枚举矩形的左右边界以固定宽度w,此时矩形的高度为h,就是所有包含在内的柱子的最小高度,对应的面积是 w x h
class Solution1
{
public:
	int largestRectangleArea(vector<int>& heights)
	{
		int n = heights.size();//n是矩阵的个数
		int ans = 0;
		for (int left = 0; left < n; left++)//枚举左边界
		{
			int minHeight = INT_MAX;
			for (int right = left; right < n; right++)
			{
				minHeight = min(minHeight, heights[right]);//确定最大矩形的高度
				ans = max(ans, (right - left + 1) * minHeight);//计算最大矩形的面积
			}
		}
		return ans;
	}
};

//方法二--- 枚举高(超时
//用一重循环枚举某一根柱子,将其固定为矩形的高度h,随后我们从这根柱子开始向两侧延申,直到遇到高度小于h的柱子,此时就会确定矩形的左右边界;
//最大矩形的面积表示为 w x h
class Solution2
{
public:
	int largestRectangleArea(vector<int>& heights)
	{
		int n = heights.size();
		int ans = 0;
		for (int i = 0; i < n; i++)
		{
			int height = heights[i];//以下标为i的位置的矩形开始向左右两侧延申 以此来寻找左右边界
			int left = i, right = i;
			while (left - 1 >= 0 && heights[left-1] >= height)--left;//确定左边界
			while (right + 1 < n && heights[right + 1] >= height)++right;//确定右边界
			ans = max(ans, (right - left + 1) * height);//有几个矩形就会计算几次面积 取这些面积中的最大值
		}
		return ans;
	}
};

//方法三 -- 单调栈解法 (提交成功
//单调递增栈的操作方法
//如果新的元素比栈顶元素大 就入栈
//如果新的元素较小 那就一直把栈内元素弹出来 直到栈顶比新元素小
// 
//加入这样一个规则后:
//栈内元素是递增的,从栈底到栈顶递增
//当元素出栈时,说明这个新元素是出栈元素向后找第一个比其小的元素
//元素出栈后,说明新的栈顶元素是出栈元素向前找第一个比其小的元素

class Solution
{
public:
	int largestRectangleArea(vector<int>& heights)
	{
		stack<int>s;
		int ans = 0;
		heights.push_back(0);//考虑特殊的输入,输入的本身就是递增的,这里的操作会强制这种情况下计算面积;
		for (int i = 0; i < heights.size(); i++)
		{
			while (!s.empty() && heights[s.top()] >= heights[i])//新遍历到的元素对应的高度比栈顶元素对应的高度小
			{
				int h = heights[s.top()];
				s.pop();
				if (s.empty())
				{
					ans = max(ans, i * h);
				}
				else
				{
					ans = max(ans, (i - s.top() - 1) * h);
				}
			}
			s.push(i);//栈中存放的是元素的下标
		}
		return ans;
	}
};


leetcode 85 最大矩形H

给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
在这里插入图片描述


//寻找最大矩形并返回其面积
class Solution
{
public:
	int maximalRectangle(vector<vector<char>>& matrix)
	{
		int m = matrix.size();
		if (m == 0)return 0;
		int n = matrix[0].size(); 
		vector<vector<int>>left(m, vector<int>(n, 0));//m行n列的二维矩阵,每个位置的元素值都初始化为0  left[i][j]表示矩阵第i行j列元素左边连续1的数量;即矩阵的宽度
		for (int i = 0; i < m; i++)//遍历行 这个for循环是用来求出每一个位置的left[i][j]
		{
			for (int j = 0; j < n; j++)//遍历列
			{
				if (matrix[i][j] == '1')    //j==0表示第一列 第一列左侧连续1的个数为0
				{
					left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;//状态递推 left[i][j]表示(i,j)左侧连续1的个数
				}
			}
		}
		int res = 0;//创建一个变量表示面积
		for (int i = 0; i < m; i++) //这个for循环用来每一个位置的面积 然后取其中的最大值;
		{
			for (int j = 0; j < n; j++)
			{
				if (matrix[i][j] == '0')continue;//遇到的是0 直接跳过;只有遇到当前位置的元素为1时 才开始求left[i][j]
				int width = left[i][j];//所找矩形的宽度 就是当前的left[i][j]
				int area = width*1;//初始化一个宽度为width 高为1的矩形
				for (int k = i - 1; k >= 0; k--) //从当前位置向上找高度 遍历行
				{
					width = min(width, left[k][j]);//维护一个最小的宽度 不同的left[k][j]中取最小的那个 因为最大矩形的面积是由最小的宽度决定的
					area = max(area, (i - k + 1)*width);//维护一个最大的面积;i-k+1就是行的差值即高度;
				}
				res = max(res, area);
			}
		}
		return res;
	}
};



leetcode 221 最大正方形

寻找二维数组中最大的正方形并返回其面积
在这里插入图片描述

//动态规划解法
class Solution
{
public:
	int maximalSquare(vector<vector<char>>& matrix)
	{
		int m = matrix.size(), n = matrix[0].size();
		vector<vector<int>>dp(m, vector<int>(n, 0));
		dp[0][0] = matrix[0][0] == '1' ? 1 : 0;
		int maxn = dp[0][0];
		for (int i = 1; i < m; i++)
		{
			dp[i][0] = matrix[i][0] == '1' ? 1 : 0;
			maxn = max(maxn, dp[i][0]);
		}
		for (int j = 1; j < n; j++)
		{
			dp[0][j] = matrix[0][j] == '1' ? 1 : 0;
			maxn = max(maxn, dp[0][j]);
		}
		for (int i = 1; i < m; i++)
		{
			for (int j = 1;j < n; j++)
			{
				if (matrix[i][j] == '1')
				{
					dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
					maxn = max(dp[i][j], maxn);
				}
			}
		}
		return pow(maxn, 2);
	}
};
//================================================================================
///效率稍微低一些的解法 但是更容易理解
//如果我们能计算出所有dp(i,j) 的值,那么其中的最大值即为矩阵中只包含 1 的正方形的边长最大值,其平方即为最大正方形的面积。
//dp[i][j]的含义:以(i,j)为右下角的最长的只包含1的正方形的边长;
//二维矩阵中的最大正方形
class Solution
{
public:
	int maxSq(vector<vector<char>>& nums)
	{
		int m = nums.size();
		int n = nums[0].size();
		if (m == 0 || n == 0)return 0;
		vector<vector<int>>dp(m, vector<int>(n, 0));//dp[i][j]表示以(i,j)为右下角 且只包含1的边长的最大值;
		int maxAns = 0;//表示正方形的边长
		for (int i = 0; i < m; i++)
		{
			for (int j = 0; j < n; j++)
			{
				if (nums[i][j] == '1')
				{
					if (i == 0 || j == 0)
					{
						dp[i][j] = 1;//对于第一行或第一列的元素 最大正方形就是1x1
					}
					else
					{
						dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1])+1;//对于其他位置的1 当前位置可由左 上 左上 桑格位置递推而来 取三个中的最小值即可
					}
				}
				maxAns = max(maxAns, dp[i][j]);//维护一个最大的边长
			}
		}
		return maxAns * maxAns;
	}
};


leetcode 200 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围
在这里插入图片描述

思路:
每遇到 ‘1’的点,就开始以这个为中心向周围 (上下左右四个方向)进行搜索,并且把搜索到的每个为 ’1‘的点重新标记为’0’
深度搜索到一个点无法继续向下搜索为止,最后的那个点应该是上下左右都为0;
当一条深度搜索的路径无法向下进行时,结束搜索,继续遍历寻找下一个为'1'的节点


class Solution
{
public:
	int numIslands(vector<vector<char>>& grid) //grid数组里面存放的是 0 和 1 的字符 因此是char类型
	{
		int m = grid.size();
		if (m == 0)return 0;
		int n = grid[0].size();
		int res = 0;//存储岛屿的数量
		for (int i = 0; i < m; i++)//遍历行
		{
			for (int j = 0; j < n; j++)//遍历列
			{
				if (grid[i][j] == '1')
				{
					++res;//每进行一次深度搜索 就表示找到了一个岛屿;因为每次深搜都会搜到一个岛屿之后再结束搜索;
					dfs(grid, i, j);//当遇到一个岛屿后 以该点为中心 搜索周围的点 上下左右四个点
				}
			}
		}
		return res;
	}

public:

	int dfs(vector<vector<char>>& grid, int i, int j)
	{
		int m = grid.size();
		int n = grid[0].size();
		grid[i][j] = '0';//在搜索的过程中 每一个为 1 的位置重新标记为 0 防止重复计数
		if (i - 1 >= 0 && grid[i - 1][j] == '1')dfs(grid, i - 1, j);//上 注意不要超过上下左右的边界
		if (i + 1 < m && grid[i + 1][j] == '1')dfs(grid, i + 1, j);//下
		if (j - 1 >= 0 && grid[i][j - 1] == '1')dfs(grid, i, j - 1);//左
		if (j + 1 < n && grid[i][j + 1] == '1')dfs(grid, i, j + 1);//右
	}
};

leetcode 349 两个数组的交集 I &&leetcode 350 两个数组的交集 II

给定两个数组,返回两数组的交集,返回的数组中是不能包含重复元素的,每个值唯一;
思路:
在进行遍历比较之前,先用unordered_set进行去重
例如:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

//返回两数组中的交集 I 且返回的数组中是不能包含重复元素的 
class Solution2
{
public:
	vector<int>intersection(vector<int>& nums1, vector<int>& nums2)
	{
	  //在进行比较之前 这两个去重的操作就可以保证最后的结果是不包含重复元素的
		unordered_set<int>nums1_set(nums1.begin(), nums1.end());//unordered_set默认是不含重复元素 用这个集合相当于是去重
		unordered_set<int>nums2_set(nums2.begin(), nums2.end());//对nums2去重
		vector<int>res;
		for (int num : nums2_set)//遍历nums2去重之后的元素
		{
			if (nums1_set.find(num) != nums1_set.end())//在数组nums1中可以发现和nums2中一样的元素
			{
				res.push_back(num);//用集合
			}
		}
		return res;
	}
};

给定两数组,返回数组中的交集,返回的集合中是可以包含重复元素的,换言之,不需要去重,有几个重复元素就返回几个即可
思路:
哈希实现
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]

小注:这两个返回两数组交集的题目共同的解法思路是,先遍历一个数组,用一个哈希表记录数组元素出现的次数,再遍历另一个数组,查找是否可以在第二个数组中找到第一个数组的元素

class Solution4
{
class Solution4
{
public:
	vector<int>res;
	int mp[10086];//数组作哈希 声明位置在函数体外
	vector<int>intersect(vector<int>& nums1, vector<int>& nums2)
	{
		//unordered_map<int, int>mp; //用哈希表 声明位置在函数体内
		for (auto num1:nums1)
		{
			mp[num1]++;
		}
		for (auto num2 : nums2)
		{
			if (mp[num2])
			{
				res.push_back(num2);//找到一个相同的数字 就在哈希表中减少这个数字出现的次数 表明这个数字已经匹配了 防止下次匹配的时候重复匹配
				mp[num2]--;
			}
		}
		return res;
	}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.liang呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值