LeetCode.1713.得到子序列的最少操作数

LeetCode.1713.得到子序列的最少操作数

  • 0 前言
  • 一、理论思路
    • 1、HashMap
    • 2、寻找最大公共序列
      • 1. ArrayList
      • 2. 替代与添加
      • 3. return
      • 4. 快速查找有序表--二分法
      • 5. 算法评估
  • 二、完整源代码
    • 1、注意事项

0 前言

刷算法第四天打卡,困难题。通过查阅资料最终解答完的感受是:分析问题,联系所学基础知识与题中细节的匹配去转化问题是解决问题的核心。
LeetCode.1713.得到子序列的最少操作数_第1张图片

一、理论思路

1、HashMap

该题的target数组元素映射的下标顺序是在arr数组中寻找最大公共序列的顺序标准,所以我们用HashMap去存target数组中的元素以及下标作为

Map<Integer, Integer> m = new HashMap<>();
        for (int i = 0; i < target.length; i++) {
     
            m.put(target[i], i);
        }

2、寻找最大公共序列

1. ArrayList

通过匹配arr中的元素去寻找最大公共数组,所以我们申请一个ArrayList作为最大公共序列的接收。

List<Integer> results = new ArrayList<>();

2. 替代与添加

在匹配arr数组元素的时候,会匹配出很多子序列,而我们只需要最大那个子序列。通过ArrayList元素的添加来获取子序列的大小;通过ArrayList元素的替代来寻找其它子序列。而最终ArrayList被撑到多大,就是最大公共子序列的长度。即size()。

for (int val : arr) {
     
            if (m.containsKey(val)) {
     
                int index = m.get(val);
                int positon = binarySearch(index, results);
                //这里根据二分查找回来的值来选择是替换还是添加
                if (positon == results.size()) {
     
                    results.add(index);
                } else{
     
                    results.set(positon, index);}
            }
        }

3. return

此时我们得到了撑到最大子序列的size(),可以在arr的任意位置插入。所以返回的插入大小为target.length-size()。

return target.length - results.size();

4. 快速查找有序表–二分法

public static int binarySearch(int index, List<Integer> results) {
     
        //1. 当results没值时或者index>results.get(results.size()-1)时则表示这个元素可以直接加在results后面
        if (results.size() == 0 || index > results.get(results.size() - 1))
            return results.size();
        //2. 当上面的情况不成立时,则表示这个元素虽然在arr数组中,但是它不能加在results序列的后面,因为它不是比前面的元素都大
        //2. 此时的results的size认为是当前最大size,需要去得到新的results,此时用小的index去替代results中的元素
        //2. 直到把results的size撑到更大,或者根本就撑不大,然后又有更大的元素了。
        int low = 0, high = results.size() - 1;
        //有序表就可以二分查找,这样很快
        while (low < high) {
     
            int mid = (low + high) / 2;//为什么要+1?这里取整时默认取下,而+1操作相当于取上,这与下面判断大小的方向有关,没写好会陷入死循环
            if (index > results.get(mid)) {
     //存在一个问题是,把1插到0和4之间,到底该返回那个位置呐?我们应该往后撑起来,所以应该返回4这个位置
                low = mid + 1;
            } else
                high = mid;
        }
        return low;
    }

5. 算法评估

  1. 时间复杂度:O(n+mlogm),O(n):HashMap存值处;O(mlogm)遍历加二分查找。
  2. 空间复杂度:O(n+m),O(n):HashMap存值处;O(m)ArrayList获取最大公共子序列处。

二、完整源代码

public static int minOperations(int[] target, int[] arr) {
     
        //1. 公共序列要按target数组排序,用HashMap存target元素以及对应的下标
        Map<Integer, Integer> m = new HashMap<>();
        for (int i = 0; i < target.length; i++) {
     
            m.put(target[i], i);
        }
        //2. 通过这个这个HashMap存的下标序列去匹配arr,然后得出一个最大序列用ArrayList存起来
        List<Integer> results = new ArrayList<>();
        for (int val : arr) {
     
            if (m.containsKey(val)) {
     
                int index = m.get(val);
                int positon = binarySearch(index, results);
                //这里根据二分查找回来的值来选择是替换还是添加
                if (positon == results.size()) {
     
                    results.add(index);
                } else{
     
                    results.set(positon, index);}
            }
        }
        //3. 返回的插入数值就是target的长度减去这个公共最大序列的size
        return target.length - results.size();
    }

    public static int binarySearch(int index, List<Integer> results) {
     
        //1. 当results没值时或者index>results.get(results.size()-1)时则表示这个元素可以直接加在results后面
        if (results.size() == 0 || index > results.get(results.size() - 1))
            return results.size();
        //2. 当上面的情况不成立时,则表示这个元素虽然在arr数组中,但是它不能加在results序列的后面,因为它不是比前面的元素都大
        //2. 此时的results的size认为是当前最大size,需要去得到新的results,此时用小的index去替代results中的元素
        //2. 直到把results的size撑到更大,或者根本就撑不大,然后又有更大的元素了。
        int low = 0, high = results.size() - 1;
        //有序表就可以二分查找,这样很快
        while (low < high) {
     
            int mid = (low + high) / 2;//为什么要+1?这里取整时默认取下,而+1操作相当于取上,这与下面判断大小的方向有关,没写好会陷入死循环
            if (index > results.get(mid)) {
     //存在一个问题是,把1插到0和4之间,到底该返回那个位置呐?我们应该往后撑起来,所以应该返回4这个位置
                low = mid + 1;
            } else
                high = mid;
        }
        return low;
    }

1、注意事项

注释把思想写的很清楚,而且二分法还有两处小细节,我也标注出来了。

你可能感兴趣的:(数据机构与算法,算法,二分法,数据结构,hashmap,java)