Intern plan
内容管理
程序语言【汇编】、数组专题续【二分、双指针----> 最大连续字段】
昨天已经介绍了计算机的可靠性,计算机的子系统的连接的方式就传串联、并联等,注意可靠性R(t)和失效率λ的关系; R = e^(-λ)t ; 以及计算机的加密技术和认证技术
分析了一个双指针的复杂一点的问题,字符串比较最主要就是让index停在正确的位置等待比较,需要注意错误的情况
程序语言
程序语言概念
程序实际语言的基本成分包括数据、运算、传输、控制等;高级程序设计语言是不依赖具体的机器硬件的;只是其他的高级没有java的跨平台性,但是也是可以在不同类型的机器上都可以编写C程序的
低级语言和高级语言
这个问题其实已经是非常的浅显了,计算机识别的语言就是机器码【0、1组成】,低级语言就是机器语言和汇编语言的统称,是面向机器的语言,格式取决于计算机的机器指令,programmer难以理解,可读性不好,设计效率低
高级语言: 面向各类应用的语言,比如java、C等,这些语言对于programmer来说更加容易理解,效率较高
高就程序设计语言中,PHP就是适合处理动态网页的处理,HTML是静态网页的处理,JavaScript是编写前台的脚本
汇编、编译、解释
这几个名词也是常见的名词,还是比较容易理解的;他们都是高级程序语言翻译为计算机硬件理解的语言所使用的方式
- 汇编语言编写的: 使用汇编程序将源程序翻译为目标程序,然后执行目标程序
- 高级语言编写的,需要编译程序或者解释程序进行翻译,然后运行
编译器【javac】 将源程序翻译为目标语言程序,机器上运行的是翻译后的程序,和源程序和编译程序无关 ,java只是翻译为字节码bytecode,.class文件
解释器:直接解释执行源程序,或者翻译成某种中间代码执行,并且与逆行过程于言承旭和解释程序有关;---- 这是和编译器最大的区别
比如100行代码,解释器就是一边解释一边执行; 而编译器将100行代码编译完成之后,执行编译的程序
系统程序开发更加适合使用编译型语言
编译器生成独立的目标程序,编译完之后执行目标程序, 解释器不生成独立的目标程序,解释之后立即执行—JavaScript、python
- 编译可能闭解释效率高
- 解释方式比编译方式更加灵活、可移植性好 【java跨平台 - JVM 半编译半解释】
程序设计语言定义 — 语法、语义、语用
这几个概念还是提一下,我乍看都不知道语用是个啥
-
语法: 就是一组规则
-
语义: 静态语义—编译时可以去顶成分的含义和动态语义-----运行时才确定
-
语用: 构成语言的记号和使用者的关系
关于数据成分、运算成分、和控制成分(顺序、选择、循环)就不细说了,easy~
【特殊类型:void 用户定义类型: enum 构造类型: 数组、结构、联合 指针类型 抽象数据类型】
系统为全局变量分配的存储单元一般是不可改变的,而局部变量的存储单元是可以动态改变的
堆和栈 --- 都是动态存储 --- 局部变量
全局变量存储在静态数据区
编译过程
编译程序的作用就是将源高级语言程序翻译成与之等价的目标程序,工作过程一般分为六个阶段:
前面的词法分析、语法分析、语义分析、中间代码生成 ---- 前端 和高级语言相关; 后面的两个过程(代码优化、目标代码生成) — 后端 和机器相关
在对高级语言程序进行编译的过程中,为源程序变量分配的存储单元的地址为逻辑地址,最后运行的时候才转化为物理地址(之前的CPU的中的地址转换也是硬件和操作系统—主存和辅存)
词法分析
单词法则,就是对源程序从前到后逐个字符扫描,【从中识别出一个个单词】,单词就是程序设计语言的基本语法单位 ----- 关键字、保留字、标识符、常数、括号 ,标点符号 - 都是词法分析的内容
所以比如将int 写成了 ant ,英文分号写成中文分号,那么词法分析就发现问题,出现错误,所谓编译阶段就过不去【第一个阶段都过不去:happy:
语法分析
根据语言的语法规则(不同的语言的表达不同),在词法分析的基础上,分析单词串是否构成短语和句子,判断是否合法,同时检查语法错误; 如果源程序没有语法错误,语法分析后就可以构造出其语法树
比如for(i = 0; i < num; i ++) 这里i没有进行声明,所以编译的第二阶段就报错了
语义分析
分析各语法的结构的含义,检查源程序是否包含静态语义错误,手机类型的信息供代码生成阶段使用; 语义分析的主要工作就是进行类型的分析和检查;
比如一个int num = 11.2%2; 这个表达式没有词法错误,也没有语法错误,但是就是语义出现了问题,=后边的含义是用浮点数取余,出现了问题,类型不匹配呢
中间代码生成
根据语义分析的结果生成中间代码,常用的中间代码有: 后缀式【逆波兰式】、四元式【三地址码】、树型表示
符号表管理
符号表的作用就是记录源程序中各种符号的必要信息,辅助语义的正确性检查和代码生成,在编译过程中需要对符号表进行快速有效查找、插入、修改、删除等
//符号表的主要作用就是辅助后面的语义分析和代码检查
num int 1
num2 double 2.2
stu Student [....]
编译程序对高级语言程序进行处理的过程中,不断收集、记录和使用源程序的一些相关符号的类型和特征信息 --- 其实其存在 符号表 中
符号表就是对源程序的各个符号的必要信息进行记录
出错处理
源程序中肯定会有一些错误,分为静态错误和动态错误【在java中按照异常就是可检查异常和运行时异常】
- 动态错误发生在程序时,比如/0,下标越界 【运行时异常jav】
- 静态错误指编译阶段发生的程序错误,分为语法错误和静态语义错误
- 语法错误: 单词、符号,表达式缺少、括号缺少等easy 问题
- 静态语义错误: 语义分析时发现的运算符和运算对象不合法等
中缀、前缀、后缀
这个在二叉树变换的时候经常考【前序,中序、后序遍历】
- 中缀表达式: 就是平常使用的表达式,运算符在中间【a + b * c]
- 前缀表达式:(波兰表达式) 将运算符写在前面,操作数写在后面,且不使用括号 【先序遍历—根左右; +a*bc】
- 后缀表达式:(逆波兰式) 将运算符写在后面,操作数卸载前面,不使用括号 【后续遍历,左右根---- abc*+】 ---- 可以轻松用栈实现运算
中序表达式转为前序表达式,就是按照运算的优先级依次加上括号;然后从内向外依次变形,将操作符放在括号的前面去,操作数留下;依次执行, 最后去掉括号得到波兰式; 后缀表达式和其方法类似
中序: (a+b)*c -d
前缀表达式:(((a+b)*c)-d) ----> -(*(+(ab)c)d) ---> -*+abcd
后缀表达式: (((a+b)*c)-d) ----> (((ab)+c)*d) ---> ab+c*d
值传递和引用传递就不分析了,主要是注意包装类型和String为final修饰的;java中的对象调用就是引用传递;值传递方式下,实参可以是变量,也可以是常量和表达式
Part 2
🤭,还是先看看昨天的遗留问题,昨天的复杂度高达O(N2),如何优化呢?
同时我要纠正一下昨天的问题,不要遍历数组来判断0的情况
for(int i = 0; i < nums.length; i ++) {
sum += nums[i];
}
//正整数,那就可以直接path
if(sum < target) {
return 0;
}
这里就是因为没有正确的使用初始值min,输出的时候加一个三元表达式即可。。。。当时太急了
return min == 1000000 ? 0 : min;
滑动窗口【双指针变种】
- 博主认为这里适用于双指针之间的序列有实际意义的题目
之前分析的双指针有两种形式,一般都是用于空间复杂度为O(1)的数组删除等;分为同向行驶的,i= k = 0;还有就是相向行驶的,相向行驶终止条件就是相等的时候就完了; 这里的典型就是之前的对有序的数组【含负数】进行平方排序
而这里的滑动窗口,就是两个指针也是同向行驶,但是这里将两个指针之间的序列当作窗口,最大的窗口长度就是数组整个,这里的和之前的同向的双指针不同就是之前的双指针在意的是位置,不考虑两个指针之间的序列的意义,这里就可以考虑
这里既然都是正整数,那么两个指针之间就是待判断的序列;end指针移动之后,到达了满足targert的位置之后,start指针向后滑动,如果不满足条件,end再向后滑动;【之前的暴力解法,就是start一直向前移动,end每次移动之后的位置都被浪费了,需要重新又从start开始移动,所以多了时间的复杂度】 ---- 其实思想和记忆化搜索相同,既然之前现成的end的位置,那么就不要浪费了
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int start = 0, end = 0;
int min = Integer.MAX_VALUE;
int sum = 0;
while(end < nums.length) {//尾指针最多移动到最后
sum += nums[end];
while(sum >= target) {//这里的复杂度没有O(n),因为start++的次数是可数的,为常数
//当窗口的值大于的时候就移动前面的指针
//记录值
min = Math.min(min,end + 1 - start);
//同时将窗口序列变化
sum -= nums[start];
//删除之后变动
start ++;
}
end ++; //while循环要自己写
}
return min == Integer.MAX_VALUE ? 0 : min;
}
}
这里题目就完成了
904. 水果成篮 - 力扣(LeetCode) (leetcode-cn.com)
class Solution {
public int totalFruit(int[] fruits) {
//暴力解法就是遍历,然后还是指针遍历,判断两个指针之间的种类是不是2种的最小
//这里的要求就是两个棵树之间的满足种类为2的最大的窗口的长度
int start = 0, end = 0;
//存储种类的数组
ArrayList kindList = new ArrayList();
int kind = 0; //记录当前种类
int max = 0;
while(end < fruits.length) {
//每次就判断种类
if(!kindList.contains(fruits[end])) {
kindList.add(fruits[end]);
kind ++;
}
while(kind > 2) { //这里判断什么时候窗口尾指针不动了
//给出当前max
max = Math.max(max,end - start); //窗口的长度
kind -- ; //start的位置的种类一定是算入的
for(int i = 0; i < kindList.size(); i ++) {
if(kindList.get(i).equals(fruits[start])) {
kindList.remove(i);
}
}
start ++;
}
//考虑一下start不懂,尾指针划出的时候,这里有很多解
if(end == fruits.length) {
max = Math.max(max, end - start);
}
end ++;
}
return max;
}
}
这个题有点意思,明天继续,今天状态不好😢