算法--模拟

一、旋转数组

复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 旋转数组
     * @param n int整型 数组长度
     * @param m int整型 右移距离
     * @param a int整型一维数组 给定数组
     * @return int整型一维数组
     */
    public int[] solve (int n, int m, int[] a) {
        if (m == 0) return a;
        m = m % n;
        Stack<Integer> one = new Stack<>();
        for (int i = 0 ; i < m ; i++) {
            one.push(a[a.length - 1 - i]);
        }
        List<Integer> res = new ArrayList<>();
        for (int j = 0; j < m; j++) {
            res.add(one.pop());
        }
        System.arraycopy(a, 0, a, res.size(), a.length - res.size());
        for (int k = 0 ; k < res.size(); k++) {
            a[k] = res.get(k);
        }
        return a;
    }
}

运行结果

二、螺旋矩阵

给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。

数据范围:0≤n,m≤10,矩阵中任意元素都满足 ∣val∣≤100

要求:空间复杂度 O(nm),时间复杂度 O(nm)

复制代码
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param matrix int整型二维数组
     * @return int整型ArrayList
     */
    public ArrayList<Integer> spiralOrder (int[][] matrix) {
        // write code here
        if (matrix.length == 0)return new ArrayList<>();
        int m = matrix.length;
        int n = matrix[0].length;
        int x = 0, y = 0; // 起始位置
        int[] dx = new int[] {0, 1, 0, -1}; //行方向,右、下、左、上
        int[] dy = new int[] {1, 0, -1, 0}; //列方向
        int dir = 0; //起始方向
        ArrayList<Integer> res = new ArrayList<>();
        for (int i = 0; i < m * n; i++) {
            res.add(matrix[x][y]);
            matrix[x][y] = Integer.MAX_VALUE;

            int nx = x + dx[dir];
            int ny = y + dy[dir];

            if (nx >= m || nx < 0 || ny >= n || ny < 0 ||
                    matrix[nx][ny] == Integer.MAX_VALUE) {
                // 转向
                dir = (dir + 1) % 4;
                nx = x + dx[dir];
                ny = y + dy[dir];
            }

            x = nx;
            y = ny;
        }
        return res;
    }
}

运行结果

三、顺时针旋转矩阵

有一个NxN整数矩阵,请编写一个算法,将矩阵顺时针旋转90度。

给定一个NxN的矩阵,和矩阵的阶数N,请返回旋转后的NxN矩阵。

数据范围:0<n<300,矩阵中的值满足 0≤val≤1000

复制代码
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param mat int整型二维数组
     * @param n int整型
     * @return int整型二维数组
     */
    public int[][] rotateMatrix (int[][] mat, int n) {
        // write code here
        /*** 核心思想:旋转 = 转置 + 每行反转
        * - 转置:沿主对角线(左上→右下)交换元素
        * - 行反转:将每一行的元素左右翻转 */

        // 转置
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                int temp = mat[i][j];
                mat[i][j] = mat[j][i];
                mat[j][i] = temp;
            }
        }

        // 行反转
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n / 2; j++) {
                int temp = mat[i][j];
                mat[i][j] = mat[i][n - 1 - j];
                mat[i][n - 1 - j] = temp;
            }
        }
        return mat;
    }
}

运行结果

四、设计LRU缓存结构

设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能:

  1. Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存

  2. get(key):如果关键字 key 存在于缓存中,则返回key对应的value值,否则返回 -1 。

  3. set(key, value):将记录(key, value)插入该结构,如果关键字 key 已经存在,则变更其数据值 value,如果不存在,则向缓存中插入该组 key-value ,如果key-value的数量超过capacity,弹出最久未使用的key-value

提示:

1.某个key的set或get操作一旦发生,则认为这个key的记录成了最常使用的,然后都会刷新缓存。

2.当缓存的大小超过capacity时,移除最不经常使用的记录。

3.返回的value都以字符串形式表达,如果是set,则会输出"null"来表示(不需要用户返回,系统会自动输出),方便观察

4.函数set和get必须以O(1)的方式运行

5.为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹

复制代码
import java.util.*;

public class Solution {
    //LRU缓存设计成hashmap+双向链表结构
    Map<Integer, Node> cache = new HashMap<>(); //键为key,值是Node结点
    Node left = new Node(0, 0); //lru
    Node right = new Node(0, 0); //mr
    int cap = 0; //容量
    int len = 0; //结点个数
    public Solution(int capacity) {
        this.cap = capacity;
        left.next = right;
        right.prev = left;
    }

    public int get(int key) {
        // 通过hashmap快速找到结点,移除节点,再将结点插入最末
        if (cache.containsKey(key)) {
            Node node = cache.get(key);
            remove(node);
            return insertTail(node);
        }
        return -1;
    }

    public void set(int key, int value) {
        // 先判断是否存在,如果存在移除原节点,插入最末。
        // 否则直接插入最末。cache put(key,val)。
        // 判断len > cap,移除lru,及其hashmap  lru.key
        if (cache.containsKey(key)) {
            remove(cache.get(key));
        }
        Node node = new Node(key, value);
        insertTail(node);
        cache.put(key, node);
        if (len > cap) {
            Node lru = left.next;
            remove(lru);
            cache.remove(lru.key);
        }
    }

    public int insertTail(Node node) {
        // 插入
        Node prev = right.prev;
        prev.next = node;
        node.next = right;
        right.prev = node;
        node.prev = prev;
        len++;
        return node.val;
    }

    public int remove(Node node) {
        //移除结点
        Node prev = node.prev;
        Node next = node.next;
        prev.next = next;
        next.prev = prev;
        len--;
        return node.val;
    }
}

class Node {
    int key;
    int val;
    Node prev;
    Node next;

    Node(int key, int val) {
        this.key = key;
        this.val = val;
    }

    Node(int key, int val, Node prev, Node next) {
        this.key = key;
        this.val = val;
        this.prev = prev;
        this.next = next;
    }
}

运行结果

五、设计LFU缓存结构

一个缓存结构需要实现如下功能。

  • set(key, value):将记录(key, value)插入该结构
  • get(key):返回key对应的value值

但是缓存结构中最多放K条记录,如果新的第K+1条记录要加入,就需要根据策略删掉一条记录,然后才能把新记录加入。这个策略为:在缓存结构的K条记录中,哪一个key从进入缓存结构的时刻开始,被调用set或者get的次数最少,就删掉这个key的记录;

如果调用次数最少的key有多个,上次调用发生最早的key被删除

这就是LFU缓存替换算法。实现这个结构,K作为参数给出

复制代码
import java.util.*;

public class Solution {
    public int[] LFU(int[][] operators, int k) {
        LFUCache lfu = new LFUCache(k);
        List<Integer> res = new ArrayList<>();
        for (int[] op : operators) {
            if (op[0] == 1) {
                lfu.put(op[1], op[2]);
            } else {
                res.add(lfu.get(op[1]));
            }
        }
        return res.stream().mapToInt(Integer::intValue).toArray();
    }

    private static class LFUCache {

        private final Map<Integer, Integer> keyToFreq = new HashMap<>();
        private final Map<Integer, Map<Integer, Integer>> freqToMap = new HashMap<>();
        private final int capacity;
        private int minFreq;

        public LFUCache(int capacity) {
            this.capacity = capacity;
            this.minFreq = 1;
        }

        public int get(int key) {
            if (!keyToFreq.containsKey(key)) return -1;
            return move(key, -1);
        }

        public void put(int key, int value) {
            if (keyToFreq.containsKey(key)) {
                move(key, value);
                return;
            }
            if (keyToFreq.size() == capacity) {
                Map<Integer, Integer> map = freqToMap.get(minFreq);
                Integer removeKey = map.keySet().iterator().next();
                map.remove(removeKey);
                if (map.isEmpty()) freqToMap.remove(minFreq);
                keyToFreq.remove(removeKey);
            }
            minFreq = 1;
            if (!freqToMap.containsKey(minFreq)) freqToMap.put(minFreq,
                        new LinkedHashMap<>());
            freqToMap.get(minFreq).put(key, value);
            keyToFreq.put(key, minFreq);
        }

        private int move(int key, int value) {
            Integer freq = keyToFreq.get(key);
            Map<Integer, Integer> map = freqToMap.get(freq);
            if (value == -1) value = map.get(key);
            map.remove(key);
            if (map.isEmpty()) {
                freqToMap.remove(freq);
                if (freq == minFreq) {
                    minFreq = freq + 1;
                }
            }
            if (!freqToMap.containsKey(freq + 1)) freqToMap.put(freq + 1,
                        new LinkedHashMap<>());
            freqToMap.get(freq + 1).put(key, value);
            keyToFreq.put(key, freq + 1);
            return value;
        }
    }
}

运行结果

相关推荐
Javatutouhouduan1 小时前
阿里1658页Java面试题总结(含答案)
java·高并发·java面试·java面试题·后端开发·java程序员·java八股文
秋天的怀念_David1 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
专业程序开发源1 小时前
springboot欧缇蔓月子中心管理系统82697-计算机课程设计、毕业设计
java·spring boot·后端·python·spring·django·课程设计
秋天的怀念_David2 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
thefool1122662 小时前
网络编程^
java
薛定e的猫咪2 小时前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
薛定e的猫咪2 小时前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习
Thinker QAQ2 小时前
并发编程(十一):Shared Memory 与 Message Passing——关系与组合使用
java·python·go·并发编程·shared memory·message passing
齐 飞3 小时前
idea中git误操作撤回git reset --hard ‘HEAD@{1}‘
java·git·intellij-idea