【Review】存储系统和计算机可靠模型(加密和认证),双指针法续、最大字段(数组)

Intern plan


数组专题


昨天简单分享了计算机硬件基础和计算机组成原理的一点内容;主要就是Cache的直接、全、组映像、计算机CPU中各部件的组成,还有各部分的协作关系;需要注意IO外设和CPU程序控制方式,无条件、程序查询、中断方式需要CPU,但是DMA方式就是主存和外设;留意映像的方式,对于程序设计也有新的思考,走极端【完全对应、完全随机】都不可取,组的加入让部分有序,部分无序才能提高效率

关于指令集ISA,需要注意一些属于,比如super pipeline 超流水线、VLIW very long instruction word 超长指令字【 RISC 提倡精简,使用了超流水线技术、优化编译技术(因为由很多寄存器),采用组合逻辑;而CIRC倡导扩张,普遍采用微程序控制器

存储系统中的相联存储和hash表类似,就是可以按照内容进行存储;虚拟存储时逻辑上的,需要MMU进行转换,抽象之后便于上层的用户理解使用

存储系统和计算机可靠模型

存储系统编址

关于存储系统的编制这里需要解释一下; 内存是按照字节编址的,不是按位!!;当然一个字节等于8bit

在这里插入图片描述

这里是随手画的图,就是将一块存储当作一个宾馆,每一个字节就是房间,这些房间的标号就是从0开始的;所以只是需要知道有多少个房间就知道该用多少位的二进制数表示

这里就可以简单的应用一下;注意平时的内存B、KB、MB的B是byte不是bit;所以说内存是以字节位单位,不是位

//之前的直接映像中, 主存的地址  :  区号 + 区内块号 + 块内地址
主存容量1MB,Cache容量16kb,块的大小512B, 那么区号需要用几位表示?块号?
1MB/16KB = 64个区, 那么就需要6位二进制码来表示
16kb/512B = 32个块, 那么就需要5位二进制码表示
512B/1B = 512个字节【字节位单位】  那么就需要9位二进制表示
所以主存地址一共需要20位

地址映射【硬件】 硬件和操作系统

昨天已经提到过了Cache和主存之间的地址映射的几种方式,并且探讨了地址的存储,那么转换是什么完成的呢?

preview

主存和Cache之间的数据调动是由硬件自动完成的,对所有程序员均是透明的;

主存-辅存两级存储构成的虚拟存储器,数据映射使用的,由硬件MMU和操作系统共同完成的,主存和辅存之间的数据调动对应用程序员是透明的

安全可靠性和系统性能评测

计算机安全不只是软件安全,还有硬件和技术等多方面的知识。

不同的组织机构有不同的准则,包括美国TCSEC,加拿大的CTCPEC,欧洲的ITSEC,美国的CC被ISO批准进入国际标准;安全性级别从D1—A1多个级别【不深入分析了,欢迎探讨】

信息安全的5个要素: 机密性(信息不暴露给未授权)、完整性(允许的person才可以修改)、可用性(授权的person可以访问数据)、可控性(可以控制信息流向)、可审查性(安全问题可以调查)

常见的安全威胁: 比如窃听、媒体清理,截获、修改、信息泄露等 【 很好理解,主要是如何做出防范?】

加密技术

加密技术是常用的安全保密手段(以前战争中经常就是密报,需要约定密钥,比如摩尔斯),数据加密技术的关键在于加密/解密的算法和密钥的管理, 密钥就是加密算法传入的参数,加密过程就是将明文加密成密文再解密成明文

加密算法E,加密密钥K1,明文P,密文C    C = Ek1(P)
解密算法D,解密密钥K2,密文C,明文P   P = Dk2(C)
对称加密技术(私有密钥加密)

文件加密和解密使用的密钥是相同的,或者虽然不同,但是从其中一个可以轻松知道另外一个;【用户之间需要交换密钥,来保证密钥对称; 就是发送信息除了密文还有就是密钥

//比如现在的加密算法就是按位取反
1001 ---> 0110 --> 1001
明文       密文      明文

这里加密的密钥和解密的密钥都是相同的,对称

常用的对称加密算法:

  • 3DES: 使用两个56位的密钥
  • RC-5
  • IDEA: 国际数据加密算法 encryption algorithm 类似与DES,密钥长度128位
  • AES: 基于排列和置换运算

非对称的保密性更好,但是不适合大量的报文的加密,大量的报文还是要使用堆成加密,就是上面的几个RC-5,IDEA。。。。

img

一般加密算法都是公开的,密钥是保密的,只是知道算法,但是不知道密钥是不能正确解密的;比如f = x0 + 3*e^m -89; 这样一个简单的算法中,m参数如果不知道,那么得不到f

非对称加密(公开密钥加密)

加密密钥和解密的密钥不相同,并且加密密钥和解密密钥是一对,一个是公开密钥,一个是非公开的私有密钥,一个公开密钥对应一个唯一的解密私有密钥

非对称加密有两个不同的体制:加密模型和认证模型

查看源图像

  • 加密模型 ------ 接收方B生成一对密钥,并将其中一把进行公开,其他的任何人都可以通过某种方式获取公钥,得到公钥的发送方将机密信息加密发送给接收B,B使用私钥进行解密获取信息【其他人截获信息因为没有私钥,不能获取信息】

但是这样虽然不需要交换密钥,但是解密时间长了,只适合少量数据,文件不使用

  • 认证模型 ---- 主要用于对信息发送者的身份进行认证; 发送方生成一对密钥,加密的密钥私有,解密的密钥公开,那么任何人都可以获取到A的数据并获取内容,不能保证信息安全,但是可以认证A的身份,【比如接收者有多个公钥,用谁的公钥解开证明发送者就是谁,用于认证身份】

RSA算法就是一种公钥的加密算法,是基于大素数分解的困难性; (分解200位的素数需要40亿年)

两个个体进行互信的条件就是 互换公钥【私钥既然是私钥,当然不能告诉其他的】
A、B分别从I1、I2两个集购获得证书,A、B互信的必要条件就是 I1和I2互换公钥

信息摘要Message Digest

信息摘要就是一段信息的唯一标识【类似于人识别的指纹】,PK;

Hash函数提供支持: 输入一个长度不固定的字符串,返回的就是一串固定长度的字符串(hash值) , 单向的Hash函数就可以产生信息摘要,信息摘要唯一 【 这个之前的SSM后台就使用了MDHash函数对密码进行摘要 — 这里是不能推出原文的,所以当时的方法就是加密后再和密文比较】

在特定的时间内,无法查找经过Hash操作后生成特定Hash值得到源报文,不能查找经过Hash函数处理后结果相同得不同报文【I am Cfeng 和 I am Cfeng. 的报文摘要不同 ---- 这样一下就知道是否篡改 防止数据被篡改

所以可以使用在数字签名中,解决了签名得验证、身份验证和不可抵赖

常用得MD2、MD5、MD4、SHA-1等hash函数,产生得是128位的信息摘要 ----- 都是报文摘要算法【和报文加密算法不是同一个概念】

数字签名模型(认证模型)

数字签名主要: 信息发送者使用单向的Hash函数生成信息摘要128bit;(非对称加密的认证模型)信息发送者使用自己的私钥对加密【签名】信息摘要; 发送方将原文和签名后的密文都发送,接收方使用公钥验证【可能被第三方修改】,如果认证成功,证明没有修改

查看源图像

注意这里发送的信息就是原文和加密后的签名

数字加密模型【数字信封技术】 – 同时使用对称加密和非对称加密 (加密模型)

上面的数字签名模型只是可以进行认证,就是证明信息没有被第三方篡改,但是因为连带原文一起发送,第三方可以获取原文,信息就会泄露;

加密技术,就是发送者发送信息时,先生成一个对称密钥加密要发送的报文,然后使用接收者的公开密钥加密该对称密钥;(密钥的密钥);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OHWoBTE6-1649601820706)(https://tse1-mm.cn.bing.net/th/id/R-C.9663461bcf8beb73268d75b37a814001?rik=BS6AHwChMTyqCw&riu=http%3a%2f%2fimg.cebnet.com.cn%2f20170704%2f102405215.png&ehk=L7scoYAPM1mtrZnlgnZd%2bJoh99LxaXFZ7DiY0l0zWSg%3d&risl=&pid=ImgRaw&r=0)]

数字信封中的内容就是加密后的信息和加密后的对称密钥; 接收者使用私钥解密得到对称密钥解密得到原文,这里可以保证信息的保密性,但是不能进行认证

数字签名是认证,使用的是发送方的密钥对,可以进行认证,接收方使用公钥进行认证,只使用非对称密钥; 数字加密是加密,使用接收方的密钥对,同时使用对称和非对称;保证信息的保密性

计算机可靠性

  • 计算机系统的可靠性: 从开始运行t = 0到某时刻t这段时间内正常运行的概率,用R(t)标识

  • 计算机系统的失效率: 单位时间内失效的元件数和原件总数的比例,入 – 标识

  • 平均故障时间MTBF : 两次故障之间能正常工作的平均值 ; MTBF = 1/入

  • 计算机系统的可维修性: 一般平均修复时间MTRF来标识,从故障发生到机器修复的平均时间

  • 计算机系统的可用性: 指计算机的使用效率,使用系统执行任务时的任意时刻能正常执行的概率A标识

A = (MTBF)/(MTBF + MTRF)

计算机可靠性模型

影响计算机可靠性的因素有很多,可以位常见的系统建立可靠性模型

串联系统

一个系统由N个子系统构成,只有所有的子系统正常工作,才能够正常工作

查看源图像

所以总系统的可靠性R = R1 * R2 * R3…*Rn

总系统的失效率 入 = 入1 + 入2 + 入3 +… + 入n

并联系统

只有所有的子系统都坏掉的情况下才不能正常工作

查看源图像

所以总系统的可靠性R = 1 - 不可靠的 = 1 - (1-R1)*(1- R2) * … (Rn)

哈希函数是单向的函数  并且哈希函数是将变长的输入转化位固定长度的输出,比如MD5,都是转为128位的摘要
哈希表就是根据键值直接访问的数据结构【内容和存储位置有关】,随机预言机就是一个完美的哈希函数哟

Part 2 arithmetic

双指针

之前对于二分查找就不再解释了,二分查找的条件就是有序的序列即可,=就是3种,边界就是2种;没什么难的,主要就是要判断边界和最后到底返回的是left还是right

而双指针,就是两个index,常见的应用就是自反的要求空间复杂为O(1),有同向和相向两种,相向的效率更高,但是可能有次序的问题

844. 比较含退格的字符串 - 力扣(LeetCode) (leetcode-cn.com)

这个题目也是双指针,但是是简单的两个数组的双指针,唯一的难点就是处理退格符#

博主最开始的想法很easy,那就直接从后向前两个指针遍历即可,分相等和不等两种情况,然后碰到#退两个 ,很遗憾,考虑不周全,没有考虑连续的###的情况

所以既然是这样,那么就加个技术器来统计#的数量,每次遇到不是#且不退格的地方就停下来,等待第二个字符串停下来再比较

class Solution {
    public boolean backspaceCompare(String s, String t) {
        int i = s.length() - 1, j = t.length() - 1;
        int sSkip = 0, tSkip = 0; //计数器
        while(i >= 0 || j >= 0) { //逻辑或,因为长度只要是合法即可,考虑最开始可能是退格符
            //一个一个来,先s
            while(i >= 0) {
                if(s.charAt(i) == '#') {
                    sSkip ++;
                    i--;  //继续移动
                }else if(sSkip > 0) {
                    //如果不是#,但是还是可以退格,那就消耗机会,继续移动
                    sSkip --;
                    i --;
                }else {
                    //到这里说明不是#并且已经将退格机会用完了,那就等t来比较了
                    break;
                }
            }
            //再同理t
            while(j >= 0) {
                if(t.charAt(j) == '#') {
                    tSkip ++;
                    j --;
                } else if(tSkip > 0) {
                    tSkip --;
                    j --;
                } else {
                    break;
                }
            }

            //到这里就说明s和t可以愉快的比较了,没有退格的干扰,如果不合法就是错的;但是这里可能已经有字符串不合法了;排除false的地方
           if(i >=0 && j >= 0) {
               if(s.charAt(i) != t.charAt(j)) {
                   return false;
               }
           }else {
               if(i >= 0 || j >= 0) {
                   //一个还有,一个已经没有了
                   return false;
               }
           }
           //继续进行
           i--;
           j--;
        }
        return true;
    }
}

这里的双指针需要想清楚,首先就是上面我们需要排除#的影响,所以要使用两个计数器来进行记录,当两个字符串都停在了不是#的地方,然后再比较;这里比较的时候,可能其中的字符串的index越界了,所以需要排除,不只是不相等,有两种情况都需要排除

977. 有序数组的平方 - 力扣(LeetCode) (leetcode-cn.com)

这个题首先上来一分钟,来个暴力,马上解决

class Solution {
    public int[] sortedSquares(int[] nums) {
        //直接一个大暴力
        for(int i = 0; i < nums.length; i ++) {
            nums[i] = nums[i] * nums[i];
        }
        Arrays.sort(nums);
        return nums;
    }
}

最坏复杂度O(n2),因为内部排序使用的可能是插入排序,上面的是O(N);如何降低复杂度?

这里要看到数组本身是有序的,平方最大的都在两边,所以使用双向指针法,博主在这里将nums[end]写成end;调了好一会,害:happy:

class Solution {
    public int[] sortedSquares(int[] nums) {
        //但是这里考虑题目条件 【非递减排序,那么平方之后,最小值在中间,最大值在两边,那就用一个辅助数组,双指针同时向中间遍历】
        //空间复杂度O(n)
        int[] result = new int[nums.length];
        //相向的双指针while循环
        int begin = 0, end =nums.length - 1;
        int k = nums.length - 1; //放入新数组
        while(end > begin) {
            if(nums[end] * nums[end] > nums[begin] * nums[begin]) {
                result[k --] = nums[end] * nums[end];
                end --;
            }else if(nums[end]* nums[end] < nums[begin] * nums[begin]) {
                result[k --] = nums[begin] * nums[begin];
                begin ++;
            }else {
                result[k --] = nums[begin] * nums[begin];
                result[k --] = nums[end] * nums[end];
                begin ++;
                end --;
            }
        }
        result[0] = nums[begin] * nums[begin];
        return result;
    }
}

209. 长度最小的子数组 - 力扣(LeetCode) (leetcode-cn.com)

这里是正整数,那就直接暴力法,最坏复杂度O(N2)

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //以前觉得最大字段和问题挺难的,但是想想不就是两个指针嘛,一个移动,第二个移动当一个小弟
        //先来暴力法
        int min = nums.length; //记录结果
        int sum = 0;
        for(int i = 0; i < nums.length; i ++) {
            sum += nums[i];
        }
         //正整数,那就可以直接path
        if(sum < target) {
           return 0;
        }

        for(int i = 0; i < nums.length; i ++) {
            //i是主index
            sum = 0;
            for(int j = i; j < nums.length; j ++) {
                //从index
                sum += nums[j];
                if(sum >= target) {
                    if(j - i < min) {
                        min = j + 1 -i; //刷新
                    }
                    break; //退出从指针
                }
            }
        }
        return min;
    }
}

优化的解法明天给🎉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值