一、数组
1.数组的定义:
数组的元素类型 数组名[];
数组的元素类型[] 数组名;
int a[];
int[] a;
2.数组的初始化:
数组名=new 数组的数据类型[数组的长度];
a=new int[10];
3.数组的地址值:用数组名来表示
二、查集法
定义:一种树形数据结构,用于处理互相不相交的集合中元素的查询与合并;
解决思路:创建pre数组来存放元素的前驱节点。
int find(int x){//查找元素x的根节点
if (x==pre[x]){
return x;
}
return pre[x]=find(pre[x]);//递归
}
void union(int x,int y){//两个集合合并
int f1=find(x);//f1表示x的根节点
int f2=find(y);//f2表示y的根节点
if (f1!=f2){//表示f1和f2在不同的集合
pre[f2]=f1;
}
}
boolean isSame(int x,int y){
int f1=find(x);//f1表示x的根节点
int f2=find(y);//f2表示y的根节点
return f2==f1;
}
示例:假设有5个村庄,分别是a,b,c,d,e。其中a和b相连,b和c相连,d和e相连,请问a和e是否相连?
分析:5个村庄的连接情况如下图
可以用一个长度为5的整数型数组分别表示这5个村庄。
完整代码如下:
public class UnionFind {//查并集
static int[] pre;
public UnionFind(int capacity){//创建构造函数
pre=new int[capacity+1];//初始化
for (int i = 0; i < capacity+1; i++) {
pre[i]=i;
}
}
public int find(int x){//查找元素x的前驱节点,返回的是根节点
if (x==pre[x])return x;//递归出口:x是根节点
return pre[x]=find(pre[x]);//先找到根节点,在把前驱节点赋值给根节点
}
public void union(int x,int y){//合并x和y所在的集合
int f1=find(x);//f1表示x的根节点
int f2=find(y);//f2表示y的根节点
if (f1!=f2){//表示f1和f2在不同的集合
pre[f2]=f1;
}
}
public boolean isSame(int x,int y){//判断x和y是否在同一个集合中
int f1=find(x);//f1表示x的根节点
int f2=find(y);//f2表示y的根节点
return f2==f1;
}
}
public class A {
public static void main(String[] args) {
UnionFind unionFind = new UnionFind(5);
unionFind.union(1,2);//连线
unionFind.union(2,3);
unionFind.union(4,5);
System.out.println("判断a和e是否在同一个相连(即在同一个集合中)");
System.out.println(unionFind.isSame(1,5));
}
}
运行结果:
判断a和e是否在同一个相连(即在同一个集合中)
false
1、力扣相关题型
(1)547.省份数量
题目描述:
给出一个nxn的矩阵isConnected[n][n]表示城市的关联情况.如果isConnected[i][j]==1,则表示两个城市相连(即同属于一个省份),判断所给的矩阵涉及多少个省份并输出省份的个数。
代码:
class Solution {
public int findCircleNum(int[][] isConnected) {
if (isConnected==null||isConnected.length==0) {
return 0;
}//集合为空或者长度为0的情况
int n=isConnected.length;
UnionFind_ uf=new UnionFind_(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (isConnected[i][j]==1){
uf.union(i,j);
}
}
}
return uf.getCount();//返回矩阵的数量
}
}
//查并集
class UnionFind_{
int pre[];
int count;
UnionFind_(int size){
pre=new int[size];
count=size;
for (int i = 0; i < size; i++) {
pre[i]=i;
}
}
int find(int x){
if (x==pre[x]){
return x;
}
return pre[x]=find(pre[x]);//递归
}
void union(int x,int y){
int f1=find(x);//f1表示x的根节点
int f2=find(y);
if (f1!=f2){//若两个节点不在同一个集合中,则合并两个集合
pre[f2]=f1;//升级到根节点
count--;
}
}
int getCount(){
return count;
}
}
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
2.蓝桥杯相关题型
(1)修改数组
题目描述:给定长度为N的数组A=[A1,A2,…,An],数组中可能有重复出现的数。一次检查A2到An,当检查Ai时,遍历A1到Ai-1,如果Ai出现过则Ai加上1;如果新的Ai仍然在之前出现过则Ai继续加1.现给定初始数组及其长度,计算最终数组并且输出最终数组。
解题思路:
遍历数组元素,查找父节点,输出父节点的值,将元素的值加上1赋值给父节点。
代码:
public class Main {
static int pre[] = new int[1000001];
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();//输入第一行数据
int data[] = new int[n];
for (int i = 0; i < n; i++) {
data[i] = scan.nextInt();//输入第二行数据
}
//初始化pre
for (int i = 0; i < pre.length; i++) {
pre[i] = i;
}
for (int i = 0; i < data.length; i++) {//遍历每个元素
data[i] = find(data[i]);//找到data[i]指向的父节点
System.out.print(data[i]+" ");
pre[data[i]]=data[i]+1;//改变data[i]的父节点的值
}
scan.close();
}
static int find(int x) {//查并集:返回x的根节点
if (x == pre[x]) {//递归出口:根节点是本身
return x;
}
return pre[x] = find(pre[x]);
}
}
示例:
//输入
5
2 1 1 3 4
//输出
2 1 3 4 5