IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【动态规划】最少按多少下开关使灯全亮 -> 正文阅读

[数据结构与算法]【动态规划】最少按多少下开关使灯全亮

无环条件下

题目描述

给定一个数组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;  
    //0不变 1不变  
    int p1=processForLoop(arr,3,arr[1],arr[2],arr[arr.length-1],arr[0]);  
    //0不变 1改变  
    int p2=processForLoop(arr,3,arr[1]^1,arr[2]^1,arr[arr.length-1],arr[0]^1);  
    //0改变 1不变  
    int p3=processForLoop(arr,3,arr[1]^1,arr[2],arr[arr.length-1]^1,arr[0]^1);  
    //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++];  
        }  
    }  
    //i==arr.length-1,也就是当前的位置在arr.length-2  
    if(preState==0){  
        op++;  
        preState=curState^1;  
        endState^=1;  
        curState=endState;  
    }else{  
        preState=curState;  
        curState=endState;  
    }  
    //i==arr.length了  
    return (preState!=curState||curState!=firstState)?Integer.MAX_VALUE:(op+curState^1);  
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:59:48  更:2022-10-17 13:00:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:53:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码