无环条件下
题目描述
给定一个数组arr,长度为N,arr中的值不是0就是1
- arr[i]表示第i栈灯的状态,0代表灭灯,1代表亮灯
- 每一栈灯都有开关,但是按下i号灯的开关,会同时改变i-1、i、i+2栈灯的状态 (改变状态是指灯由原来的灭变亮和由原来的亮变灭)
问题一: - 如果N栈灯排成一条直线,请问最少按下多少次开关,能让灯都亮起来
- 排成一条直线说明:
- i为中间位置时,i号灯的开关能影响i-1、i和i+1
- 0号灯的开关只能影响0和1位置的灯
- N-1号灯的开关只能影响N-2和N-1位置的灯
解题思路
还是使用动态规划的思想,主要是递推数组的定义,因为一个开关可以影响3个开关.
所以我们要让该递推数组带上三个状态,如当前的位置是i,那么我们就要记录一下i+1位置下标,前一个的状态preState,当前的状态curState.
有了这三个状态,我们后面才方便去根据前一个位置的状态去推当前的状态,这也就是动态规划的一个最基本的思想,就是开辟多个参数来记录不同的状态
具体的变化过程:
如果preState的状态为0,那么说明我们一定要按下当前i位置的开关. 如果preState的状态为1,那么我们就不需要按下当前的i位置的开关
上面的就是递推公式,对于临界情况:
如果i到达了arr.length-1,也就是i+1到arr.length了,那么我们就要判断preState和curState的状态是否相同了.此时默认前面的状态都是1
如果不相同,那么就没有机会全亮了,直接返回Integer.MAX_VALUE 如果相同,那么如果状态为1,返回0;如果状态为0,返回1
递归版本
public int noLoopMinStep1(int[] arr){
if(arr==null||arr.length==0)
return 0;
if(arr.length==1)
return arr[0]==1?0:1;
if(arr.length==2)
return arr[0]!=arr[1]?Integer.MAX_VALUE:arr[0]^1;
int p1=process(arr,2,arr[0],arr[1]);
int p2=process(arr,2,arr[0]^1,arr[1]);
if(p2!=Integer.MAX_VALUE)
p2++;
return Math.min(p1,p2);
}
public int process(int[] arr,int nextIndex,int preState,int curState){
if(nextIndex==arr.length)
return preState!=curState?Integer.MAX_VALUE:preState^1;
if(preState==0){
curState^=1;
int cur=arr[nextIndex]^1;
int next=process(arr,nextIndex+1,curState,cur);
return next==Integer.MAX_VALUE?next:next+1;
}else{
return process(arr,nextIndex+1,curState,arr[nextIndex]);
}
}
迭代版本
public int noLoopMinStep2(int[] arr){
if(arr==null||arr.length==0)
return 0;
if(arr.length==1)
return arr[0]==1?0:1;
if(arr.length==2)
return arr[0]!=arr[1]?Integer.MAX_VALUE:arr[0]^1;
int p1=process2(arr,arr[0],arr[1]);
int p2=process2(arr,arr[0]^1,arr[1]);
if(p2!=Integer.MAX_VALUE)
p2++;
return Math.min(p1,p2);
}
private int process2(int[] arr, int preState, int curState) {
int i=2;
int count=0;
while(i<arr.length){
if(preState==0){
count++;
preState=curState^1;
curState=arr[i++]^1;
}else {
preState=curState;
curState=arr[i++];
}
}
return preState!=curState?Integer.MAX_VALUE:(count+preState^1);
}
有环状态下
题目描述
和前面的题目一样,不同的是收尾相连是一个环.
解题思路
加上了环之后,我们最大的问题就是修改0位置的时候会影响尾,修改尾的时候会影响头.对于其他位置的元素和没环的时候是一致的.
递归版本
主函数: 我们从2下标开始,是因为想要在递归中避开firstIndex的影响.所以在主函数中单独的对0和1下标进行更改.因为只有0和1会影响到firstIndex的值,从2开始之后都不会影响到firstIndex的值
public int LoopMinStep(int[] arr){
if(arr==null||arr.length==0)
return 0;
if(arr.length==1)
return arr[0]==1?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[1]!=arr[2]?Integer.MAX_VALUE:arr[0]^1;
int p1=processForLoop(arr,3,arr[1],arr[2],arr[arr.length-1],arr[0]);
int p2=processForLoop(arr,3,arr[1]^1,arr[2]^1,arr[arr.length-1],arr[0]^1);
int p3=processForLoop(arr,3,arr[1]^1,arr[2],arr[arr.length-1]^1,arr[0]^1);
int p4=processForLoop(arr,3,arr[1],arr[2]^1,arr[arr.length-1]^1,arr[0]);
p1=p1==Integer.MAX_VALUE?Integer.MAX_VALUE:p1++;
p2=p2==Integer.MAX_VALUE?Integer.MAX_VALUE:p2++;
p1=p3==Integer.MAX_VALUE?Integer.MAX_VALUE:p3++;
p1=p4==Integer.MAX_VALUE?Integer.MAX_VALUE:p4++;
return Math.min(Math.min(p1,p2),Math.min(p3,p4));
}
因为有环的原因,所以我们又新加了两个状态firstState和endState. 当我们到达arr.length-2下标时,也就是nextIndex=arr.length-1时,会对endState有影响,这一点注意就好了
public int processForLoop(int[] arr,int nextIndex,int preState,int curState,int endState,int firstState){
if(nextIndex==arr.length)
return (preState!=curState||curState!=firstState)?Integer.MAX_VALUE:endState^1;
if(preState==0){
int next=processForLoop(arr,nextIndex+1,curState^1,
nextIndex==arr.length-1?endState^1:arr[nextIndex]^1,
nextIndex==arr.length-1?endState^1:endState,firstState);
return next==Integer.MAX_VALUE?Integer.MAX_VALUE:next+1;
}else {
return processForLoop(arr,nextIndex+1,curState,arr[nextIndex], endState,firstState);
}
}
迭代版本
还是从i=3开始,还是要注意i=arr.length-1的时候的endState的值
public static int processForLoop(int[] arr,int preState,int curState,int endState,int firstState){
int i=3;
int op=0;
while (i<arr.length-1){
if(preState==0){
preState=curState^1;
curState=arr[i++]^1;
op++;
}else{
preState=curState;
curState=arr[i++];
}
}
if(preState==0){
op++;
preState=curState^1;
endState^=1;
curState=endState;
}else{
preState=curState;
curState=endState;
}
return (preState!=curState||curState!=firstState)?Integer.MAX_VALUE:(op+curState^1);
}
|