记录:2022-9-10 完美数 快乐数 括号生成 请求调页 页面置换 写时复制 页面缓冲算法

这篇博客探讨了算法优化的策略,包括使用单调队列提升DP问题的效率,例如在解决滑动窗口最大值问题时。此外,还讲解了请求调页和页面置换的概念,详细阐述了缺页处理的过程及其性能影响。文章介绍了写时复制技术,用于在页面共享时避免不必要的副本创建,从而提高效率。最后,讨论了几种页面置换算法,如FIFO、最优页面置换和LRU,并分析了它们的优缺点。
摘要由CSDN通过智能技术生成

学习时间 2022-9-10

学习内容

1、leetcode 两道简单题 一道中等题

在这里插入图片描述
优化是靠的退出时机,当除出来的数已经小于除数时,说明后续的已经不需要继续做了,并且如果除出来的余数为0,说明这两个数都是正因子

class Solution {
    public boolean checkPerfectNumber(int num) {
        int ans = 1;
        if(num == 1){
            return false;
        }
        for(int i = 2;i<num;i++){
            int num2 = num / i;
            if(num2 <= i){
                break;
            }
            if(num % i == 0){
                //可以找到两个正因子
                ans += i;
                ans += num2;
            }
        }
        if(ans == num) return true;
        return false;
    }
}

在这里插入图片描述
如果不是快乐数,他在循环的过程中会重复某个值,这就导致他无法回到1

class Solution {
    public boolean isHappy(int n) {
        //中途若出现循环 则结束
        HashSet<Integer> set = new HashSet<Integer>();
        while(n != 1){
            n = getNext(n);
            if(set.contains(n)){
                return false;
            }
            set.add(n);
        }
        return true;
    }
    public int getNext(int n){
        int sum = 0;
        while(n != 0){
            int s1 = n%10;
            sum+=s1*s1;
            n = n/10;
        }
        return sum;
    }
}

在这里插入图片描述
我的解法(暴力枚举)

class Solution {
    public List<String> generateParenthesis(int n) {
        HashSet<String> set = new HashSet<String>();
        set.add("()");
        //滑动窗口
        for(int i = 1;i<n;i++){
            HashSet<String> newSet = new HashSet<String>();
            for(String s : set){
                newSet.add("("+s+")");
                for(int j = 0;j<=s.length();j++){
                    newSet.add(s.substring(0,j)+"()"+s.substring(j,s.length()));
                }
            }
            set = newSet;
        }
        return new ArrayList(set);
    }
}

这个题我更愿意用回溯,因为动态规划的最优子结构不好找 不过目前暂时不太会回溯,先贴个答案

class Solution {
        List<String> res = new ArrayList<>();
        public List<String> generateParenthesis(int n) {
            if(n <= 0){
                return res;
            }
            getParenthesis("",n,n);
            return res;
        }

        private void getParenthesis(String str,int left, int right) {
            if(left == 0 && right == 0 ){
                res.add(str);
                return;
            }
            if(left == right){
                //剩余左右括号数相等,下一个只能用左括号
                getParenthesis(str+"(",left-1,right);
            }else if(left < right){
                //剩余左括号小于右括号,下一个可以用左括号也可以用右括号
                if(left > 0){
                    getParenthesis(str+"(",left-1,right);
                }
                getParenthesis(str+")",left,right-1);
            }
        }
    }

2、单调队列优化DP问题

当0<=j<i时,可以用单个变量代替dp数组进行维护
当i-j<=j<=i时(两头变),此时可以使用单调队列维护状态:
假设这个栈是单调减的,头部的元素最大,则可以这样定义:如果头部index过期,则头部出,元素从尾部进,如果他遇到了比进去的元素更小的元素,则可以说明队列中元素不需要了(只需要最大的,如果进的那个元素已经大于队列尾部的元素,说明尾部的元素已经轮不到前面了)
这个解法并不只是在DP中作优化,本身单调队列也可以做一种解法
如滑动窗口最大值问题,就可以用单调队列代替查找,每一次循环将会减少k此循环,从O(mk) -> O(m)

3、请求调页 页面置换 写时复制

请求调页

概念

一种只加载需要的页的技术,常常用于虚拟内存系统
从未访问的那些页从不加载到物理内存中
当调用不存在在内存中的页面时,将会发生缺页错误
缺页错误的解决方法如下:

  1. 检查进程的内部表,确定该引用是有效还是无效
  2. 如果无效,终止进程,如果引用有效但是没有调入页面,则现在调入
  3. 找到一个空闲帧
  4. 调度一个磁盘操作(I/O),以将所需页面读到刚分配的帧
  5. 当磁盘读取完成时,修改内部表和页表,以指示该页现在处于内存中
  6. 重启被中断的指令
性能

缺页发生动作如下:

  1. 抛出异常
  2. 保存用户寄存器和进程状态
  3. 确定中断是否为缺页错误
  4. 检查页面引用是否合法,并确定页面的磁盘位置
  5. 从磁盘读到空闲帧
  6. 在等待时,将CPU分配给其他用户(CPU调度 可选)
  7. 收到来自IO子系统的中断(完成IO)
  8. 保存其他用户的寄存器和进程状态
  9. 确定该中断来自上述磁盘
  10. 修正页表和其他表,表示目前已经在内存中
  11. 等待CPU再次分配给本进程
  12. 恢复用户寄存器 进程状态 页表,重新执行指令
    在这里插入图片描述

缺页处理时间主要由三部分构成:

  1. 处理错误中断(1-100ms)
  2. 读入页面
  3. 重新启动进程(1-100ms)

这种算法很需要降低缺页的错误率

由于移动操作系统内存较小,所以不支持交换

写时复制

页面共享,有可能绕过请求调页(如fork函数),这种情况可以采用写时复制技术,让进程在最开始拥有一样的副本,意味着当进程写入了共享页面,就创建共享页面的副本

在这里插入图片描述

页面置换

页面置换有多种算法,这个算法是当发生缺页错误时,发现了空闲帧列表没有空闲位置,这时候需要换出一个空闲位置,这个位置如何去找的不同策略。不同的算法效率不同。

FIFO页面置换

选择最旧的页面更新
性能不太理想 可能可以和其他算法配合使用 比如页面缓冲算法 不过这个算法理解很简单
在这里插入图片描述

最优页面置换

最优置换可以说是最好的算法,但是由于很难找到这个整体的最优解,所以一般很难实现。他的思想是置换最长时间不会使用的页面,这个最长是根据全局而言
这个算法一般用于比较其他的算法,毕竟这个是最优的
在这里插入图片描述

LRU(Last-Recent-Used)最近最少使用算法

使用的最多的算法,只看局部上的最少使用,并换掉他。(时间上向后看的最优页面置换算法)
这种算法在硬件层面上需要一定的支持,对于硬件来说,要确定由上次使用时间定义的帧的顺序。
在这里插入图片描述

近似LRU算法

由于很少有操作系统可以提供LRU的硬件支持,所以使用近似LRU算法,这个算法近似于LRU,通过检查引用位来确定哪些页面被使用,用引用位来代替时间定义的帧序。

基于计数的页面置换

页面置换算法还有很多,基于计数的页面置换是为每个页面引用次数保存一个计数器

LFU 最不经常使用页面置换算法

置换有最小计数的页面,策略:积极使用的页面拥有较大的计数

MFU 最经常使用算法

置换有最小计数的页面,策略:最小的页面是刚刚进入并且没有被使用频繁

页面缓冲算法

这不是一个页面置换算法,而是另外一个策略(措施):系统保留一个空闲帧缓冲池,当出现缺页错误,会选择一个牺牲帧。在写出之前,所需页面就可以读到来自缓冲池的空闲帧,这样可以让程序更加快速的启动。当牺牲帧以后被写出,它会被添加到空闲帧池

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值