LeetCode-第八个星期

戳印序列

LeetCode936题,通过一个印章将一串文字印盖成最终所需的字符串。

你想要用小写字母组成一个目标字符串 target。 

开始的时候,序列由 target.length 个 '?' 记号组成。而你有一个小写字母印章 stamp。

在每个回合,你可以将印章放在序列上,并将序列中的每个字母替换为印章上的相应字母。你最多可以进行 10 * target.length  个回合。

举个例子,如果初始序列为 "?????",而你的印章 stamp 是 "abc",那么在第一回合,你可以得到 "abc??"、"?abc?"、"??abc"。(请注意,印章必须完全包含在序列的边界内才能盖下去。)

如果可以印出序列,那么返回一个数组,该数组由每个回合中被印下的最左边字母的索引组成。如果不能印出序列,就返回一个空数组。

例如,如果序列是 "ababc",印章是 "abc",那么我们就可以返回与操作 "?????" -> "abc??" -> "ababc" 相对应的答案 [0, 2];

另外,如果可以印出序列,那么需要保证可以在 10 * target.length 个回合内完成。任何超过此数字的答案将不被接受。

 

示例 1:

输入:stamp = "abc", target = "ababc"
输出:[0,2]
([1,0,2] 以及其他一些可能的结果也将作为答案被接受)
示例 2:

输入:stamp = "abca", target = "aabcaca"
输出:[3,0,1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/stamping-the-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析:
1.逆向思想:考虑如何将target字符变为???这种形式的
2.首先找到target字符中完全匹配的字符串,将这个范围内的所有字符变为?
3.再次循环时是?的字符串则不需要考虑了,只需要考虑部分匹配的字符串
4.记录每次盖章的位置,倒序得到最终答案

 public static int[] movesToStamp(String stamp, String target) {
        char[] S = stamp.toCharArray();
        char[] T = target.toCharArray();
        //保存最终结果的倒序
        List<Integer> res = new ArrayList<>();
        //记录是否访问过
        boolean[] visited = new boolean[T.length];
        //被替换的个数
        int count = 0;
        //如果没有全部替换掉就接着循环
        while (count < T.length) {
            //标记
            boolean replaceFlag = false;
            for (int i = 0; i <= T.length - S.length; i++) {
                //如果该点没有被访问,并且可以被替换
                if (!visited[i] && canReplace(S, i, T)) {
                    //盖章,并返回盖住的字符
                    int temp = doReplace(S.length, i, T);
                    replaceFlag = true;
                    count += temp;
                    visited[i]=true;
                    res.add(i);
                    //该范围内的已经完全匹配了
                    i += temp - 1;
                    if (count == T.length) {
                        break;
                    }
                }
            }
            //如果一轮循环都没有盖过一次,则说明不能替换
            if (!replaceFlag) {
                return new int[]{};
            }
        }
        int[] resArray = new int[res.size()];
        for (int i = 0; i < res.size(); i++) {
            resArray[i] = res.get(res.size() - i - 1);
        }
        return resArray;
    }

    private static int doReplace(int len, int i, char[] t) {
        int count=0;
        for (int j = 0; j < len; j++) {
            //如果当前字符不为*,就将他变为*
            if (t[j + i] != '*') {
                t[j + i] = '*';
                count++;
            }
        }
        return count;
    }

    private static boolean canReplace(char[] s, int i, char[] t) {
        for (int j = 0; j < s.length; j++) {
            //如果在印章长度范围内,如果出现没有盖过章的字符,并且对应下标的字符不相等,则说明不能盖章
            if (t[i + j] != '*' && t[i + j] != s[j]) {
                return false;
            }
        }
        return true;
    }

数组中的逆序对

LeetCode1528题,求一个数组中降序排列的数有几对。
在这里插入图片描述
思路分析:
1.将数组nums不断的拆分,拆成最小的一个数组
2.将数组里的元素进行排序后,通过两个指针,对子数组进行遍历排序比较
3.排序比较结束后,当前这个子数组肯定是有序的,并且计算了该子数组的逆序对
4.之后计算更大规模的数组时,也是按照上面的步骤进行循环计算

 public static int reversePairs(int[] nums) {
       int len = nums.length;
       if (len < 2) {
           return 0;
       }
       return reversePairs(nums, 0, len - 1, new int[len]);
   }

   private static int reversePairs(int[] nums, int left, int right, int[] temp) {
       if (left == right) {
           return 0;
       }
       //求出中间下标值
       int mid = (left + right) >> 1;
       //计算左边子数组的逆序对(返回的子数组左边和右边肯定是有序的了)
       int lc = reversePairs(nums, left, mid, temp);
       //计算右边子数组的逆序对
       int rc = reversePairs(nums, mid + 1, right, temp);
       int count = lc + rc;
       //如果左边最大的数小于右边最小的数,则说明整个子数组都是有序的
       if (nums[mid] <= nums[mid + 1]) {
           //则直接返回总数,不用在排序合并了
           return count;
       }
       //否则将左右子数组排好序,并且计数整个数组的逆序对
       return count + mergeAndCount(nums, left, mid, right, temp);
   }

   private static int mergeAndCount(int[] nums, int left, int mid, int right, int[] temp) {
       //将left right范围内的元素存入临时数组中
       for (int i = left; i <= right; i++) {
           temp[i] = nums[i];
       }
       int res = 0;
       //左边第一个数
       int l = left;
       //右边第一个数
       int r = mid + 1;
       //循环排序并计数
       for (int i = left; i <= right; i++) {
           if (l > mid) {//说明左子数组的元素已经重新放入到nums中了,只需要取右边的数即可
               nums[i] = temp[r++];
           } else if (r > right) {//说明右子数组的元素已经重新放入到nums中了,只需要取左边的数即可
               nums[i] = temp[l++];
           } else if (temp[l] <= temp[r]) {//如果右边的数大于等于左边的数,后移左指针并将左元素放入nums中
               nums[i] = temp[l++];
           } else {//如果右边的数小于左边的数,后移右指针并将右元素放入nums中,并且计算逆序对,注意如果temp[l]>temp[r],那么左子数组中l后面的元素肯定也大于temp[r]
               nums[i] = temp[r++];
               res += (mid - l) + 1;
           }
       }
       return res;
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
城市应急指挥系统是智慧城市建设的重要组成部分,旨在提高城市对突发事件的预防和处置能力。系统背景源于自然灾害和事故灾难频发,如汶川地震和日本大地震等,这些事件造成了巨大的人员伤亡和财产损失。随着城市化进程的加快,应急信息化建设面临信息资源分散、管理标准不统一等问题,需要通过统筹管理和技术创新来解决。 系统的设计思路是通过先进的技术手段,如物联网、射频识别、卫星定位等,构建一个具有强大信息感知和通信能力的网络和平台。这将促进不同部门和层次之间的信息共享、交流和整合,提高城市资源的利用效率,满足城市对各种信息的获取和使用需求。在“十二五”期间,应急信息化工作将依托这些技术,实现动态监控、风险管理、预警以及统一指挥调度。 应急指挥系统的建设目标是实现快速有效的应对各种突发事件,保障人民生命财产安全,减少社会危害和经济损失。系统将包括预测预警、模拟演练、辅助决策、态势分析等功能,以及应急值守、预案管理、GIS应用等基本应用。此外,还包括支撑平台的建设,如接警中心、视频会议、统一通信等基础设施。 系统的实施将涉及到应急网络建设、应急指挥、视频监控、卫星通信等多个方面。通过高度集成的系统,建立统一的信息接收和处理平台,实现多渠道接入和融合指挥调度。此外,还包括应急指挥中心基础平台建设、固定和移动应急指挥通信系统建设,以及应急队伍建设,确保能够迅速响应并有效处置各类突发事件。 项目的意义在于,它不仅是提升灾害监测预报水平和预警能力的重要科技支撑,也是实现预防和减轻重大灾害和事故损失的关键。通过实施城市应急指挥系统,可以加强社会管理和公共服务,构建和谐社会,为打造平安城市提供坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值