数据库缓存

题目描述

缓存是一种提高数据库查询效率的手段,现使用训练数据进行模拟访问,以对缓存机制进行优化。
模拟访问规则如下:

  • 当查询的数据在缓存中时,直接访问缓存,无需访问数据库。
  • 当查询的数据不在缓存中时,则需要访问数据库,并把数据放入缓存:
若放入前缓存已满,则必须先删除缓存中的一个数据。

给定缓存大小和训练数据(一组数据编号),依次模拟访问这组数据,请分析在此访问规则下最少的数据库访问次数。

解答要求

时间限制:3000ms, 内存限制:256MB

输入

第一行:整数 cacheSize,表示缓存大小,范围为 [1,100]
第二行:整数 num,表示训练数据的个数,范围为 [0,1000]
第三行:num 个整数,表示训练数据的每个数据编号,编号取值范围为 [0,1000]

假设每个数据在缓存中占用的空间都是 1 。

输出

一个整数,代表数据库的最少访问次数。

样例

输入样例 1

2
6
1 2 3 1 2 3

输出样例 1

4

提示样例 1

缓存容量大小为2,依次处理待查询的训练数据:
第一次查询数据1,此时缓存中无此数据,需从数据库中读取,结束后缓存内容为1。
第二次查询数据2,此时缓存中无此数据,需从数据库中读取,结束后缓存内容为1 2。
第三次查询数据3,此时缓存中无此数据,需从数据库中读取;此时缓存已满,必须先删除一个数据(选择删除2),然后把新的数据放入,结束后缓存内容为1 3。
第四次查询数据1,此时缓存中有此数据。
第五次查询数据2,此时缓存中无此数据,需从数据库中读取,并且删除缓存中一个数据,然后放入新的数据,结束后缓存内容为2 3。
第六次查询数据3,此时缓存中有此数据。

一共访问了4次数据库,是最优解。其它缓存方式并非最优解。

输入样例 2

1
4
100 200 100 200

输出样例 2

4

Java算法源码

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.stream.Collectors;

public class QueryDatabaseCache {
    // 参照数据
    List<Integer> idsList = new ArrayList<>();
    // 方案一
    private int queryDatabase(int cacheSize, int[] ids) {
        idsList = Arrays.stream(ids).boxed().collect(Collectors.toList());
        int idsLength = ids.length;
        if (idsLength <= 1) {
            return idsLength;
        }
        // 缓存存储
        List<Integer> cacheList = new LinkedList<>();
        // 数据库查询次数
        int queryDatabaseNum = 0;
        for (int i = 0; i < idsLength; i++) {
            int id = ids[i];
            if (cacheList.contains(id)) {
                continue;
            }
            // 缓存没有满
            if (cacheList.size() < cacheSize) {
                cacheList.add(id);
            } else { // 缓存满了
                int removeIndex = deleteItem(cacheList, i);
                cacheList.remove(removeIndex);
                cacheList.add(id);
            }
            queryDatabaseNum++;
        }
        return queryDatabaseNum;
    }

    private int deleteItem(List<Integer> cacheList, int index) {
        int maxIndexToDelete = 0;
        int deleteIndex = 0;
        for (int i = 0; i < cacheList.size(); i++) {
            int nextIndex = nextIndexOf(idsList, cacheList.get(i), index);
            if (nextIndex == -1) {
                return i;
            }
            if (nextIndex > maxIndexToDelete) {
                maxIndexToDelete = nextIndex;
                deleteIndex = i;
            }
        }
        return deleteIndex;
    }

    // 方案二
    private int queryDatabase2(int cacheSize, int[] ids) {
        Map<Integer, List<Integer>> sequenceMap = new HashMap<>(ids.length);
        for (int i = 0; i < ids.length; i++) {
            int id = ids[i];
            if (!sequenceMap.containsKey(id)) {
                sequenceMap.put(id, new ArrayList<>());
            }
            sequenceMap.get(id).add(i);
        }
        Map<Integer, Boolean> cache = new HashMap<>(2);
        int queryDbTimes = 0;
        for (int id : ids) {
            sequenceMap.get(id).remove(0);
            if (cache.get(id) != null) {
                continue;
            }
            queryDbTimes++;
            if (cache.size() < cacheSize) {
                cache.put(id, true);
                continue;
            }
            Integer maxId = -1;
            Integer val = -1;
            for (Integer idKey : cache.keySet()) {
                if (sequenceMap.get(idKey).isEmpty()) {
                    maxId = idKey;
                    break;
                }
                if (sequenceMap.get(idKey).get(0) > val) {
                    maxId = idKey;
                    val = sequenceMap.get(idKey).get(0);
                }
            }
            cache.remove(maxId);
            cache.put(id, true);
        }
        return queryDbTimes;
    }

    public static int nextIndexOf(List<Integer> list, int num, int index) {
        if (list.lastIndexOf(num) <= index) {
            return -1;
        }
        List<Integer> subList = list.subList(index + 1,list.size());
        return index + 1 + subList.indexOf(num);
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in, StandardCharsets.UTF_8.name());
        int size = cin.nextInt();
        int length = cin.nextInt();
        int[] ids = new int[length];
        for (int i = 0; i < length; i++) {
            ids[i] = cin.nextInt();
        }
        cin.close();
        int maxSum = new QueryDatabaseCache().queryDatabase(size, ids);
        System.out.println(maxSum);
        System.out.println(new QueryDatabaseCache().queryDatabase2(size, ids));
    }
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

软软的铲屎官

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值