岛问题(递归) 并查集 kmp算法

1、岛问题:一个矩阵中只有0和1两种值,每个位置都可以和自己的上下左右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?

递归:

package hh;

public class Demo {
	public static int countIslands(int[][] m) {
		if(m==null || m[0]==null) {//此处不要忘记判断
			return 0;//没有数组或数组中无值
		}
		int x=m.length;
		int y=m[0].length;
		int res=0;
		for(int i=0;i<x;i++) {
			for(int j=0;j<y;j++) {
				if(m[i][j]==1) {
					res++;
					infect(m,i,j,x,y);
				}
			}
		}
		return res;
	}
	
	public static void infect(int[][] m,int i,int j,int x,int y) {
		if(i<0 || i>=x || j<0 || j>=y || m[i][j]!=1) {//m[i][j]为2或者0
			return;
		}
		//i,j没越界,且当前位置为1
		m[i][j]=2;
		infect(m,i-1,j,x,y);//感染上
		infect(m,i+1,j,x,y);//下
		infect(m,i,j-1,x,y);//左
		infect(m,i,j+1,x,y);//右
	}
	
	public static void main(String[] args) {
		int[][] m1= {
				{1,1,1,1,1,1,1,1},
				{1,0,0,0,0,0,0,1},
				{1,0,1,1,1,1,1,1},
				{1,0,1,0,0,0,0,0},
				{1,0,1,1,1,1,1,1},
				{1,0,0,0,0,0,0,1},
				{1,1,1,1,1,1,1,1}
		};
		System.out.println(countIslands(m1));
		
		int[][] m2= {
				{1,1,1,1,1,1,1,1},
				{1,0,0,0,0,0,0,1},
				{1,0,0,1,1,1,1,1},
				{1,0,1,0,0,0,0,0},
				{1,0,1,1,1,1,1,1},
				{1,0,0,0,0,0,0,1},
				{1,0,1,1,1,1,1,0}
		};
		System.out.println(countIslands(m2));
	}
}
//1
//3

2、并查集结构

package hh;

import java.util.*;

public class Demo {
	public static class Element<V>{//泛型,样本进来会包一层,为一个元素
		public V value;
		public Element(V value) {
			this.value=value;
		}
	}
	
	public static class UnionFindSet<V> {//并查集结构
		public HashMap<V,Element<V>> elementMap;
		public HashMap<Element<V>,Element<V>> fatherMap;
		public HashMap<Element<V>,Integer> sizeMap;//代表节点和归属它的总节点数
		//代表节点其实就像一个树的根
		
		public UnionFindSet(List<V> list) {//初始化
			elementMap=new HashMap<>();
			fatherMap=new HashMap<>();
			sizeMap=new HashMap<>();
			
			for(V value:list) {
				Element<V> element=new Element<V>(value);
				elementMap.put(value, element);
				fatherMap.put(element, element);
				sizeMap.put(element, 1);
			}
		}
		
		//返回element的代表节点,一路往上找,向上过程中进行扁平化优化
		private Element<V> findHead(Element<V> element){
			Stack<Element<V>> path=new Stack<>();//用栈存沿途经过的节点
			Element<V> father=fatherMap.get(element);
			while(father!=element) {
				path.add(element);
				element=father;
				father=fatherMap.get(element);
			}
			
			while(!path.isEmpty()) {
				fatherMap.put(path.pop(), element);
			}
			
			return element;
		}
		
		public boolean isSameSet(V a,V b) {//判断a、b是否为同一集合
			if(elementMap.containsKey(a) && elementMap.containsKey(b)) {//注意前提:a、b有初始化,包了一层
				return findHead(elementMap.get(a))==findHead(elementMap.get(b));
			}
			
			return false;
		}
		
		public void union(V a,V b) {//合并
			if(elementMap.containsKey(a) && elementMap.containsKey(b)) {
				Element<V> n1=findHead(elementMap.get(a));
				Element<V> n2=findHead(elementMap.get(b));
				
				//不同集合才合并,即有不同的代表节点
				if(n1!=n2) {
					int size1=sizeMap.get(n1);
					int size2=sizeMap.get(n2);
					Element<V> big=size1>size2? n1:n2;
					Element<V> small=big==n1? n2:n1;
					fatherMap.put(small, big);//big挂到small下
					sizeMap.put(big, size1+size2);
					sizeMap.remove(small);
				}
			}
		}
	}
}

3、KMP算法

package hh;

import java.util.*;

public class Demo {
	public static int getIndexOf(String s,String m) {
		if(s==null || m==null || m.length()<1 || s.length()<m.length()) {
			return -1;
		}
		char[] s1=s.toCharArray();
		char[] s2=m.toCharArray();
		int[] next=getNextArray(s2);
		int i1=0;
		int i2=0;
		while(i1<s1.length && i2<s2.length) {
			if(s1[i1]==s2[i2]) {
				i1++;
				i2++;
			}else if(i2==0) {//若不相等,回跳   //条件也可以为next[i2]==-1
				//若i2已指向s2的0位置,是无法回跳的
				i1++;//换i1下一个字符和i2比较
			}else {//可以回跳的情况
				i2=next[i2];
			}
		}
		
		return i2==s2.length? i1-i2:-1;
	}
	
	//求每个字符前(不包括该字符)最长前后缀匹配长度
	public static int[] getNextArray(char[] ms) {
		if(ms.length==1) {
			return new int[] {-1};
		}
		//长度至少为2
		int[] next=new int[ms.length];
		next[0]=-1;
		next[1]=0;
		int i=2;
		int cn=0;//cn保存当前和i-1位置比较的位置,第一次循环应为0,1位置比,以保存第2位置的信息
		while(i<ms.length) {
			if(ms[cn]==ms[i-1]) {
				next[i]=cn+1;
				i++;
				cn++;//cn同时也是i位置的最长前后缀匹配长度,保存供i+1位置使用
			}else if(cn==0) {//cn已经跳到了ms的0位置,仍然与i-1位置上的字符不相等
				next[i++]=0;
				//next[i]=0;
				//i++;                                                           -
			}else {
				cn=next[cn];
			}
		}
		return next;
	}
	public static void main(String[] args) {
		String s1="abcabcababaccc";
		String s2="abac";
		System.out.println(getIndexOf(s1,s2));//8
		
		String s11="abbsabbcabbsabbe";
		String s22="abbsabbcabbsabbw";
		System.out.println(getIndexOf(s11,s22));
		//-1
		
		String s3="11111112";
		String s4="12";
		System.out.println(getIndexOf(s3,s4));//6
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值