数据结构与算法——数组

一、数组

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值