目录
学校的班级个数
手推7个班级,答案17?怀疑人生
破案了,应该是6个班。
破案了,原来写的是 unionxy(a, b, father);
c++ if两个数同时为正或为负 简洁写法
可以用位运算?
c++可以这样赋值吗?a=b=2
修改说明:
解释:
warning: ^ has lower precedence than <; < will be evaluated first [-Wparentheses] 22 | if((p->val-root->val)^(q->val-root->val)<0) | ^~~~~~~~~~~~~~~~~~~~~怎么办
解释:
c++函数传入Vector《int》 在函数里面修改vector可以吗
1. 按值传递(修改不会影响原始向量)
2. 按引用传递(修改会影响原始向量)
3. 按常量引用传递(如果不需要修改向量)
三目
题目
学校的班级个数
通过数
1696
提交数
3677
难度
中等
显示标签
题目描述
现有一个学校,学校中有若干个班级,每个班级中有若干个学生,每个学生只会存在于一个班级中。如果学生A
和学生B
处于一个班级,学生B
和学生C
处于一个班级,那么我们称学生A
和学生C
也处于一个班级。
现已知学校中共n个学生(编号为从1
到n
),并给出m组学生关系(指定两个学生处于一个班级),问总共有多少个班级。
输入描述
第一行两个整数n、m(1≤n≤100,1≤m≤100),分别表示学生个数、学生关系个数;
接下来m行,每行两个整数a和b(1≤a≤n,1≤b≤n, a≠b),表示编号为a
的学生和编号为b
的学生处于一个班级。
输出描述
输出一个整数,表示班级个数。
样例1
输入
复制
5 3 4 2 1 3 2 5
输出
复制
2
解释
编号2
、4
、5
的学生在同一个班级,编号1
、3
的学生在同一个班级,因此共有两个班级。
手推7个班级,答案17?怀疑人生
不服来战?
57 46 22 20 20 46 9 22
41 3030 4 42 48 30 5 41 6 29 5050 4 5 1 49 5 41 48 24 56 23 56 21 8 3 9 24 21 12 21 11 49
31 40 10 31 51 13 10 13
45 52
37 2 15 3737 33 26 27 33 26 55 15 55 2727 38 43 5454 2 54 26 54 36
14 19
44 32
破案了,应该是6个班。
答案17是把没出现的人一人一班。。。
1班
57:1
57:3
57:4
57:5
57:6
57:8
57:9
57:11
57:12
57:20
57:21
57:22
57:23
57:24
57:29
57:30
57:41
57:42
57:46
57:48
57:49
57:50
57:56
57:57
7:7
2班
13:51
13:10
13:13
13:31
13:40
16:16
17:17
18:18
3班
19:19
19:14
25:25
28:28
34:34
4班
32:32
32:44
35:35
5班
38:26
38:2
38:15
38:27
38:33
38:36
38:37
38:38
38:43
38:54
38:55
39:39
47:47
6班
52:45
52:52
53:53
破案了,原来写的是 unionxy(a, b, father);
因为他编号从1开始,你不减一会数组越界 unionxy(a-1, b-1, father);
-1立马完美通过
#include<stdio.h>
#include<bits/stdc++.h>
#include<vector>
using namespace std;vector<int> init(int n)
{vector<int> father(n,1);//父亲都初始化为自己for(int i=0;i<n;i++)father[i]=i;return father;
}
int findFather(int a,vector<int>& father)
{int x=a;//记录该节点while(a!=father[a])a=father[a];int f=father[a];//记录根节点a=x;while(a!=father[a]){int temp = father[a];father[a] = f;a = temp;}//压缩路径return f;
}
void unionxy(int a,int b,vector<int>& father)
{//while(a!=father[a])a=father[a];father[findFather(a,father)]=findFather(b,father);findFather(a,father);
}
int main()
{int n,m,a,b,num=0;//cout<<n<<m;scanf("%d %d",&n,&m);
vector<int> father=init(n);for (int j=0;j<m;j++){scanf("%d %d",&a,&b);unionxy(a-1,b-1,father);}for(int i=0;i<n;i++)if(father[i]==i)num++;printf("%d",num);}
c++ if两个数同时为正或为负 简洁写法
ChatGLM
在C++中,要判断两个数同时为正或同时为负,可以使用逻辑运算符来实现简洁的写法。假设有两个整数变量 a
和 b
,可以使用以下代码:
cpp
复制
if ((a > 0 && b > 0) || (a < 0 && b < 0)) {// 两个数同时为正或同时为负
}
这段代码的逻辑是:
(a > 0 && b > 0)
检查a
和b
是否同时为正。(a < 0 && b < 0)
检查a
和b
是否同时为负。||
运算符表示“或”,即只要满足其中一个条件,整个条件就为真。
这样就可以简洁地判断两个数是否同时为正或同时为负。
访客_c53a24
可以用位运算?
ChatGLM
是的,可以使用位运算来简洁地判断两个数是否同时为正或同时为负。这种方法利用了符号位的概念。在大多数计算机系统中,整数的符号位是最高位,正数的符号位为0,负数的符号位为1。
假设有两个整数变量 a 和 b,可以使用以下代码:
c
复制
if (((a ^ b) >= 0)) {// 两个数同时为正或同时为负
}
解释:
a ^ b
是按位异或操作。如果 a 和 b 的符号位相同(即同时为正或同时为负),那么a ^ b
的符号位将为0,整个结果将是一个非负数。- 因此,
((a ^ b) >= 0)
将在 a 和 b 同时为正或同时为负时为真。
这种方法利用了位运算的特性,避免了显式的条件判断,从而更加简洁高效。
访客_c53a24
c++可以这样赋值吗?a=b=2
ChatGLM
在C++中,你可以使用链式赋值,即连续给多个变量赋相同的值。所以,a = b = 2
是合法的,并且会将 2
赋值给 b
,然后再将 b
的值赋给 a
。
例如:
cpp
int a, b;
a = b = 2;
std::cout << a << " " << b << std::endl; // 输出: 2 2
这行代码的执行顺序如下:
b = 2
:将2
赋值给b
。a = b
:将b
的值(现在是2
)赋值给a
。
因此,a
和 b
最终都会被赋值为 2
。
访客_c53a24
典型数组越界报错:Line 1122: Char 34: runtime error: addition of unsigned offset to 0x502000000190 overflowed to 0x50200000018c (stl_vector.h) SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_vector.h:1131:34class Solution { public: int search(vector<int>& nums, int target) { int n=nums.size(); int left=-1,right=n-1,x=nums[n-1]; int mid = left+(right-left)/2;int m = nums[mid]; while(left+1<right) { mid = left+(right-left)/2; m = nums[mid]; if(target<=m) { if(target==m){right=mid;break;} if(target<=x&&x<m) left= mid-1;else right=mid; }else {if(target>x&&x>=m) right=mid-1;else left=mid;} } return (right<n&&right>=0&&nums[right]==target)?right:-1; } };
你遇到的错误与向量(数组)索引计算时的溢出有关。这通常发生在当你尝试用一个超出有效范围的索引去访问向量中的元素,或者在进行索引相关的算术运算时发生了溢出。
在你的代码里,问题可能出在 mid
(中间索引)的计算上,或者 left
(左边界)和 right
(右边界)这两个索引的维护上。我们来检查一下代码,并进行修改,以确保索引始终在有效的范围内。
下面是修改后的代码版本,包含了一些改进,可以更好地处理索引问题:
cpp
复制
#include <vector>
using namespace std;class Solution {
public:int search(vector<int>& nums, int target) {int n = nums.size();if (n == 0) return -1; // 如果数组为空,直接返回-1int left = 0, right = n - 1; // 初始化左边界为0,右边界为最后一个元素的索引int x = nums[n - 1]; // 获取最后一个元素的值(虽然在这个修正版本里暂时用不到,但保留)while (left <= right) { // 循环条件:只要左边界不越过右边界就继续int mid = left + (right - left) / 2; // 计算中间索引,这样写可以避免整数溢出int m = nums[mid]; // 获取中间位置的元素值if (m == target) {return mid; // 如果中间元素正好是目标值,直接返回它的索引} else if (m < target) {left = mid + 1; // 如果中间元素小于目标值,说明目标在右半部分,调整左边界} else {right = mid - 1; // 如果中间元素大于目标值,说明目标在左半部分,调整右边界}}return -1; // 如果循环结束都没找到,返回-1表示目标不在数组中}
};
修改说明:
- 初始检查:增加了一个检查,如果传入的向量是空的(大小为0),直接返回-1,避免后续操作出错。
- 初始化:将
left
初始化为0,right
初始化为n - 1
(数组的最后一个有效索引),确保它们一开始就在合法的范围内。 - 循环条件:将循环条件改为
left <= right
。这意味着只要left
不大于right
,循环就会继续。当left
最终等于right + 1
时,循环结束,表明已经搜索了所有可能的位置。 - Mid 计算:计算
mid
的方式改为left + (right - left) / 2
。这种写法比(left + right) / 2
更安全,因为它先计算right - left
,这个差值通常比left + right
小得多,不容易溢出,尤其是在left
和right
都很大的时候。 - 比较逻辑:简化了比较逻辑。直接检查
mid
位置的元素m
是否等于target
。如果不等于,根据m
与target
的大小关系,将搜索范围缩小到左半部分或右半部分。
这个修改后的代码版本应该能正确处理索引,避免你之前遇到的溢出问题。如果你的问题依然存在,请提供更多的上下文信息或者具体的错误信息,我会尽力提供进一步的帮助。
访客_c53a24
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { auto dfs=[&](this auto&& dfs,TreeNode* root)-> TreeNode* { if(root==q||root==q||root==NULL)return root; TreeNode* l = dfs(root->left); TreeNode* r = dfs(root->right); if(l!=NULL&&r!=NULL)return root;else return (l!=NULL)? l: r; }; return dfs(root); } };哪里有错
ChatGLM
你的代码有几个小错误和可以改进的地方:
-
在
if(root==q||root==q||root==NULL)
这一行中,root==q
出现了两次,应该是root==p
和root==q
。 -
在
if(l!=NULL&&r!=NULL)return root;else return (l!=NULL)? l: r;
这一行中,逻辑可以简化,因为如果l
和r
都不为NULL
,那么root
就是最低公共祖先。否则,返回l
或r
中不为NULL
的那个。
以下是修正后的代码:
cpp
复制
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {auto dfs = [&](this auto&& dfs, TreeNode* root) -> TreeNode* {if (root == nullptr) return nullptr;if (root == p || root == q) return root;TreeNode* left = dfs(root->left);TreeNode* right = dfs(root->right);if (left != nullptr && right != nullptr) return root;return left != nullptr ? left : right;};return dfs(root);}
};
解释:
- 初始检查:如果
root
是nullptr
,直接返回nullptr
。 - 找到目标节点:如果
root
是p
或q
,返回root
。 - 递归搜索:递归搜索左子树和右子树。
- 确定最低公共祖先:
- 如果左子树和右子树都找到了目标节点,那么当前节点就是最低公共祖先。
- 否则,返回左子树或右子树中找到的目标节点。
这样修改后,代码逻辑更加清晰,并且能够正确找到最低公共祖先。
访客_c53a24
if((p->val-root->val)^(q->val-root->val)<0)
warning: ^ has lower precedence than <; < will be evaluated first [-Wparentheses] 22 | if((p->val-root->val)^(q->val-root->val)<0) | ^~~~~~~~~~~~~~~~~~~~~怎么办
ChatGLM
这个警告是因为 ^
(按位异或)运算符的优先级低于 <
(小于)运算符。为了避免这种歧义,应该使用括号明确表达式的优先级。
在你的代码中,(p->val - root->val) ^ (q->val - root->val) < 0
这一行,应该明确 (p->val - root->val)
和 (q->val - root->val)
的异或操作优先于 <
操作。
以下是修正后的代码:
cpp
if (((p->val - root->val) ^ (q->val - root->val)) < 0)
// 你的代码逻辑
;
解释:
- 使用额外的括号
((p->val - root->val) ^ (q->val - root->val))
来确保异或操作优先于比较操作。 - 这样可以避免优先级问题,并且代码更加清晰。
这样修改后,编译器就不会再发出警告,并且代码的逻辑也更加明确。
访客_c53a24
c++函数传入Vector《int》 在函数里面修改vector可以吗
ChatGLM
是的,在C++中,你可以将一个 std::vector<int>
传递给函数,并在函数内部修改它。默认情况下,如果你直接传递 std::vector<int>
,它是按值传递的,这意味着函数内部会创建一个该向量的副本,对副本的修改不会影响原始向量。
如果你想在函数内部修改原始向量,你可以使用引用传递。以下是两种方法:
1. 按值传递(修改不会影响原始向量)
cpp
复制
#include <vector>
#include <iostream>void modifyVector(std::vector<int> vec) {vec.push_back(4); // 修改的是副本
}int main() {std::vector<int> myVector = {1, 2, 3};modifyVector(myVector);// myVector 仍然是 {1, 2, 3}for (int num : myVector) {std::cout << num << " ";}return 0;
}
2. 按引用传递(修改会影响原始向量)
cpp
复制
#include <vector>
#include <iostream>void modifyVector(std::vector<int>& vec) {vec.push_back(4); // 修改的是原始向量
}int main() {std::vector<int> myVector = {1, 2, 3};modifyVector(myVector);// myVector 现在是 {1, 2, 3, 4}for (int num : myVector) {std::cout << num << " ";}return 0;
}
3. 按常量引用传递(如果不需要修改向量)
如果你只是想在函数内部读取向量,而不需要修改它,可以使用常量引用传递:
cpp
复制
#include <vector>
#include <iostream>void printVector(const std::vector<int>& vec) {for (int num : vec) {std::cout << num << " ";}std::cout << std::endl;
}int main() {std::vector<int> myVector = {1, 2, 3};printVector(myVector);// myVector 仍然是 {1, 2, 3}return 0;
}
引用
总结:
- 按值传递:函数内部修改的是副本,不影响原始向量。
- 按引用传递:函数内部修改的是原始向量。
- 按常量引用传递:函数内部只能读取向量,不能修改。
根据你的需求选择合适的方式传递向量。
三目
偶会报错
cout << (findFather(k, father) == findFather(j, father)) ? "Yes" : "No" << endl;
解决方法是加个括号
cout << ((findFather(k, father) == findFather(j, father)) ? "Yes" : "No" )<< endl;