leetcode 切分数组

题目要求:

给定一个整数数组 nums ,小李想将 nums 切割成若干个非空子数组,使得每个子数组最左边的数和最右边的数的最大公约数大于 1 。为了减少他的工作量,请求出最少可以切成多少个子数组。

示例 1:
输入:nums = [2,3,3,2,3,3]
输出:2
解释:最优切割为 [2,3,3,2] 和 [3,3] 。第一个子数组头尾数字的最大公约数为 2 ,第二个子数组头尾数字的最大公约数为 3 。

示例 2:
输入:nums = [2,3,5,7]
输出:4
解释:只有一种可行的切割:[2], [3], [5], [7]
限制:
1 <= nums.length <= 10^5
2 <= nums[i] <= 10^6

原题链接

方法一

思路:动态规划,上三角存储。bp[i][j]表示从i到j最小分割次数。
关系式:bp[i][j]=min(bp[i][k]+bp[k][j]) 其中i<=k<=j。
这里给的是一种思路。其实不用二维数组,一维数组即可。
代码如下(超时了。)

public static void main(String[] args) {
	// TODO Auto-generated method stub
//		int f[]= {2,3,3,2,3,3};
	int f[]= {326614,489921};
//		int []f= {2,3,3};
	System.out.println(splitArray(f));
}
private static List<Integer> list;
private static int [][] bp;
public static int splitArray(int[] nums) {
	int i=0,j;
	int len=nums.length;
	bp=new int[len+1][len+1];
	setPrimeNumber();
	for(i=1;i<=len;i++)
		bp[i][i]=1;
	for(i=2;i<=len;i++) {
		for(j=i-1;j>0;j--) {
			if(check(nums[j-1],nums[i-1])) { //满足要求  最大公约数大于1
				bp[j][i]=1;
			}
			else if(i-j==1) {
				bp[j][i]=2;
			}
			else {
				int min=Integer.MAX_VALUE;
				for(int k=j+1;k<=i;k++) {
					if(min>bp[j][k-1]+bp[k][i]) {
						min=bp[j][k-1]+bp[k][i];
					}
				}
				bp[j][i]=min;
			}
		}
	}
	return bp[1][len];
   }
public static void setPrimeNumber() {
	list=new ArrayList<Integer>();
	int len=1000050;
	boolean[] state=new boolean[len];
	Arrays.fill(state, false);
	state[2]=true;
	for(int i=2;i<len;i++) {
		if(state[i]) 
			continue;
		list.add(i);
		for(int j=i;j<len;j+=i) {
			state[j]=true;
		}
	}
}

public static boolean check(int n,int m){	
	if(n==m)
		return true;
	int min=Math.min(n, m);
	
	int data;
	for(int i=0;i<list.size();i++) {
		data=list.get(i);
		if(data>min)
			break;
		if(n%data==0&&m%data==0) {
			return true;
		}
	}
	return false;
	
}

方法二

思路:

  • 首先遍历一般数组,找到最大值。并且在primefactor中对应nums[i]下标创建list。它用来存储可分解的因子。
  • 然后通过质数刷,往已经存放的list中放入它的因子。
  • 开始动态规划计算。多一个数会有两种情况:一种是新增的数为一个新数组(1+bp[i-1]),还有一种情况便是新增的数于前面的的某个区间组合成新数组(1+bp[k] 0<=k<=i)。
  • 将两种情况的最小值写入bp[i]
  • 更新哈希表中的质数启示信息。例如数组{2,3,6},6之前哈希表中数据为{2=0,3=1}。处理完6之后哈希表应该是{2=2,3=2}。因为6时的切分数组更短,为1。

代码如下

public static void main(String[] args) {
	// TODO Auto-generated method stub
//		int f[]= {2,3,5,7};
//		int f[]= {3,5,2,3,2};
//		int f[]= {2,2};
	System.out.println(splitArray(f));
}
private static boolean judge[];
private static Map<Integer, Integer> primeNumberMap;
public static int splitArray(int[] nums) {
	primeNumberMap=new HashMap<Integer, Integer>();//存储质数对应的起始下标
	List<Integer> [] primefactor=new List[1000010];// 存取每个i时的因子
	// 找到nums中最大值
	int max=-1;
	for(int i=0;i<nums.length;i++) {
		if(nums[i]>max)
			max=nums[i];
		if(primefactor[nums[i]]==null)
			primefactor[nums[i]]=new ArrayList<Integer>();
	}
	judge=new boolean[max+1];//质数中间变量判断    true为质数,false为其他
	Arrays.fill(judge, true);
	//  存储质数
	for(int i=2;i<=max;i++) {
		if(!judge[i]) 
			continue;
		primeNumberMap.put(i, -1);// 初始化,
		if(primefactor[i]!=null)
			primefactor[i].add(i);
		for(int j=i+i;j<=max;j+=i) {//把质数对应的i排除在外
			judge[j]=false;
			if(primefactor[j]!=null)
				primefactor[j].add(i);
		}
	}
	int bp[]=new int[nums.length+1];//存储中间结果,从0到i需要的最小步长   偏移为1
	bp[0]=0;
	int onecount,twocount;
	for(int i=0;i<nums.length;i++) {
		twocount=1+bp[i];
		for(int prime:primefactor[nums[i]]) {
			int index=primeNumberMap.get(prime);
			if(index==-1){//第一次出现
				primeNumberMap.put(prime, i);
				onecount=bp[i]+1;
			}
			else 
				onecount=bp[index]+1;
			if(twocount>onecount)
				twocount=onecount;
		}
		bp[i+1]=twocount;
//			 更新
		for(int prime:primefactor[nums[i]]) {
			int index=primeNumberMap.get(prime);
			if(twocount<1+bp[index])
				primeNumberMap.put(prime, i);
		}
	}
	return bp[nums.length];
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值