记录:2022-9-16 格雷编码 LRU缓存机制 有效的括号 Java中的线程安全 内存工作 分段 文件系统实现 目录实现

学习时间:2022-9-16

学习内容

1、leetcode

格雷编码

在这里插入图片描述
自己写的回溯,但是遇到了问题,不知道如何判断是否相差一位,另外,并不需要求所有解,所以其实没必要用回溯

class Solution {
/*
    N = 3;
    000  0
    001  1
    011  3
    010  2

    110  6
    111  7
    101  5
    100  4 
*/

    public List<Integer> grayCode(int n) {
        List<Integer> res = new ArrayList<>();
        res.add(0); 
        if(n == 0)      return res;

        int c = 1;

        while(c <= n)
        {
            int index = res.size()-1;
            while(index >= 0)
                res.add(res.get(index--) + (int)Math.pow(2,c-1));
            
            c++;
        }
        return res;
    }
}

LRU缓存机制

在这里插入图片描述
对应Java中的LinkedHashMap结构
主要实现方法:由一个双向链表和一个HashMap

class LRUCache extends LinkedHashMap<Integer, Integer>{
    private int capacity;
    
    public LRUCache(int capacity) {
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity; 
    }
}

我的解:单哨兵 正常解法应该设置两个哨兵,这样最节约时间,不设置哨兵将非常难做

class LRUCache {
    //双向链表+hashMap
    int capacity = 0;
    Node head;//头指向最新进入
    Node tail;//尾指向最久未调用
    HashMap<Integer,Node> map;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<Integer,Node>();
        this.head = new Node(0,-1);//哨兵 key=-1
        this.tail = this.head;
    }
    
    public int get(int key) {
        //如果存在,则返回,并将key换到头部
        if(!this.map.containsKey(key)){
            return -1;
        }
        Node node = this.map.get(key);
        if(head.next == node){
            //已经在最前面了 修改值即可返回
            return node.value;
        }
        if(node==tail){
            //尾部
            tail = node.pre;//不可能会导致tail变到head上
        }
        node.pre.next = node.next;
        if(node.next != null){
            node.next.pre = node.pre;
        }
        node.pre = head;
        node.next = head.next;
        head.next.pre = node;
        head.next = node;
        return node.value;
    }
    
    public void put(int key, int value) {
        //判断是否存在该元素
        if(this.map.containsKey(key)){
            //存在,则移动到队伍头部
            Node node = this.map.get(key);
            node.value = value;
            if(head.next == node){
                //已经在最前面了 修改值即可返回
                this.map.put(key,node);
                return;
            }
            if(node==tail){
                //尾部
                tail = node.pre;//不可能会导致tail变到head上
            }
            node.pre.next = node.next;
            if(node.next != null){
                node.next.pre = node.pre;
            }
            node.pre = head;
            node.next = head.next;
            head.next.pre = node;
            head.next = node;
            this.map.put(key,node);
        }else{
            //判断当前是否已满
            if(this.capacity == this.map.size()){
                //去除一个尾部元素
                Node dropNode = tail;
                tail = tail.pre;
                tail.next = null;
                map.remove(dropNode.key);
            }
            //新加入元素移动到头部
            Node newNode = new Node(value,key);
            if(head.next != null){
                head.next.pre = newNode;
            }
            newNode.next = head.next;
            head.next = newNode;
            newNode.pre = head;
            map.put(key,newNode);
            if(tail == head){
                tail = newNode;//没有元素时,需要tail后移
            }
        }
    }
}
class Node {
    public Node next;
    public Node pre;
    public int value;
    public int key;
    Node(int value,int key){
        this.value = value;
        this.key = key;
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

有效的括号

在这里插入图片描述

栈 或者双指针

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<Character>();
        for(int i = 0;i<s.length();i++){
            if(stack.size() == 0){
                stack.push(s.charAt(i));
            }else{
                char left = stack.peek();
                if(s.charAt(i) == '(' || s.charAt(i) == '[' || s.charAt(i) == '{'){
                    //为左边
                    stack.push(s.charAt(i));
                    continue;
                }
                if(isEqual(left,s.charAt(i))){
                    //可以匹配,则弹出一个
                    stack.pop();
                }else{
                    return false;
                }
            }
        }
        if(stack.size() == 0){
            return true;
        }
        return false;
    }
    public boolean isEqual(char left,char right){
        //是否可以配对
        if(left == '(' && right ==')') return true;
        if(left == '[' && right ==']') return true;
        if(left == '{' && right =='}') return true;
        return false;
    }
}

41. 缺失的第一个正数

在这里插入图片描述
原地哈希,将数组视为hash表,然后就可以做这个题了
同类题:
442. 数组中重复的数据
448. 找到所有数组中消失的数字

原地hash,第一次遍历的时候改变数组为hash,即将元素放置在value-1的位置,如1,则放在index=0,index=0的值和1所在的值交换,通过这一轮循环以后,就可以全部放在他合适的位置上了,若发现找不到合适下标的元素,则说明该地方缺失,返回index+1,若都不缺失,则返回length+1(此题中负数直接pass)

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n; ++i) {
            if (nums[i] <= 0) {
                nums[i] = n + 1;
            }
        }
        for (int i = 0; i < n; ++i) {
            int num = Math.abs(nums[i]);
            if (num <= n) {
                nums[num - 1] = -Math.abs(nums[num - 1]);
            }
        }
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        return n + 1;
    }
}

2、Java中的线程安全是什么意思

java中的线程安全是什么: 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问 ,也就是加上了锁(类似写锁)

3、内存工作 分段

先说内存的工作,由于代码可能写入的相对地址,但实际CPU调用时不可能调用相对地址,是需要调用实际地址的,这就出现了一个问题,我们需要让空闲的空间跑代码,假设有两个进程中都用到了相对地址[100],但他们不能都在实际地址为100的地方,因为没有办法确定那个位置是否是空闲的,所以需要重定位,重定位需要区分,在什么时候进行,如编译时,载入时,运行时,但编译时会导致程序只能放在一个空闲固定的位置上,载入时重定位将导致载入后程序无法移动,所以采用运行时重定向的方法。运行时重定向实现需要在内存中采用基址+偏移的方式,将基址存入PCB中,这样就可以保证在运行时也可以移动内存。
分段是在此基础上进行的,因为分段更加符合人们的思考方式:每一种代码段都是从他自己的0开始,每一个进程中都有多个代码段,每个代码段对应的是一个地址,分段结构为<段号:段内偏移>,每一个进程会有一个LDT图,如下所示:
在这里插入图片描述
这张图会记录每一个段的基址、长度、段号等信息,而每一个进程其实在操作系统中也有一个段号,操作系统的进程段表被称为GDT,因此,分段的内存实现方式就是采用GDT+LDT的方式实现的
在这里插入图片描述

4、文件系统实现 目录实现

文件系统实现

文件控制块(FCB)

包含所有者、权限、文件内容等

内存中的文件系统结构

在这里插入图片描述

虚拟文件系统

操作系统支持多种类型的文件系统,所以需要将多个类型的文件系统集成到目录结构中,实现方法如图所示:
在这里插入图片描述

使用一个VFS(Virtual File System)接口,使通用操作和实现分开,通过这个办法,可以在不知道它处理的是什么对象的情况下对这些对象进行操作

目录实现

有两种方式可以实现:
1、线性表 查找慢,可以加缓存优化
2、哈希表 查找快(O(n)),但是对大小有要求(冲突、扩容)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值