线性和环形连接灯泡开灯问题

前提:给定一个数组arr,长度为N,arr中的值不是0就是1.arr[i]表示第i栈灯的状态,0表示灭灯,1表示亮灯。每一盏灯都有开关,但是按下i号灯的开关会改变i-1,i,i+1栈灯的状态。

问题一:如果N栈灯排成一条直线,请问最少按下多少次开关,能让灯都亮起来i为中间位置时,i号灯的开关能影响i-1,i,i+1,0号灯的开关只能影响0和1位置的灯N-1号灯只能影响N-2和N-1位置的灯。

思想:迭代法,通过记录前一位状态和当前状态,迭代交替的遍历发现为状态零则进行转变,每转变一次计数加一,到最后判断当前状态是否等于前一状态,等于则返回计数值,不等于则返回无穷。函数主体进行俩中状态的比较一种是改变当前状态,一种是不做改变,看哪种返回值最小。

代码

​
	public static int noloopRight3(int[] arr) {
		if(arr.length == 1) {
			return arr[0] ^ 1;
		}else if(arr.length == 2) {
			return arr[0] !=arr[1] ? Integer.MAX_VALUE: arr[0] ^ 1;
		}
		//不改变状态
		int p1 = iteraterLight(arr, arr[0], arr[1]);
		int p2 = iteraterLight(arr, arr[0] ^ 1, arr[1] ^ 1);
		p2 = p2 == Integer.MAX_VALUE? p2 : p2 +1;
		return Math.min(p1, p2);
	}
	public static int iteraterLight(int[] arr, int proStatus, int curStatus) {
		int i = 2;
		int op = 0;
		while(i < arr.length) {
			if(proStatus == 0) {
				op++;
				proStatus = curStatus ^ 1;
				curStatus = arr[i++] ^ 1;
			}else {
				proStatus = curStatus;
				curStatus = arr[i++];
			}
		}
		return proStatus != curStatus ? Integer.MAX_VALUE: op + curStatus ^ 1;
	}

​

问题二:如果N栈灯排成一个圈,请问最少按下多少次开关,能让灯都亮起来 i为中间位置时,i号灯的开关能影响i-1,i,i+1,0号灯的开关能影响N-1,0和1位置的灯,N-1号灯能影响0,N-2和N-1位置的灯。

思想:同样迭代法,与方法一相比要多考虑几种情况多输入起始位置状态,终止位置状态。在循环迭代完要再进行一次终止位置的判断,就是在考虑proStatus==0和!=0的情况。然后函数主体pro从arr[1]开始cur从arr[2]开始。分别讨论0位置状态是否改变和1位置状态是否改变四种情况。

代码:

public static int haveloopLight3(int[] arr) {
		if(arr.length == 1) {
			return arr[0] ^ 1;
		}
		if(arr.length == 2) {
			return arr[0] != arr[1] ? Integer.MAX_VALUE : arr[0] ^ 1;
		}
		if(arr.length == 3) {
			return arr[0] != arr[1] || arr[0] !=arr[2]? Integer.MAX_VALUE : arr[0] ^ 1;
		}
		
		int p1 = iteraterLight2(arr, arr[1], arr[2], arr[0], arr[arr.length-1]);
		//0变1不变
		int p2 = iteraterLight2(arr, arr[1] ^ 1, arr[2], arr[0] ^ 1, arr[arr.length-1] ^ 1);
		//0不变1变
		int p3 = iteraterLight2(arr, arr[1] ^ 1, arr[2] ^ 1, arr[0] ^ 1, arr[arr.length-1]);
		//0变1变
		int p4 = iteraterLight2(arr, arr[1], arr[2] ^ 1, arr[0], arr[arr.length - 1] ^ 1);
		p2 = p2 == Integer.MAX_VALUE? p2 : p2 + 1;
		p3 = p3 == Integer.MAX_VALUE? p3 : p3 + 1;
		p4 = p4 == Integer.MAX_VALUE? p4 : p4 + 2;
		return Math.min(Math.min(p1, p2), Math.min(p3, p4));
	}
	public static int iteraterLight2(int[] arr,int proStatus, int curStatus, int firstStatus,int endStatus) {
		int index = 3;
		int op = 0;
		while(index < arr.length) {
			if(proStatus == 0) {
				op++;
				proStatus = curStatus ^ 1;
				curStatus = arr[index++] ^ 1;
			}else {
				proStatus = curStatus;
				curStatus = arr[index++];
			}
		}
		if(proStatus == 0) {
			proStatus = curStatus ^ 1;
			endStatus  ^= 1;
			curStatus = endStatus;
		}else {	
			proStatus = curStatus;
			curStatus = endStatus;
		}
		return firstStatus != endStatus || proStatus != curStatus ? Integer.MAX_VALUE : op + curStatus ^ 1; 
		}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值