贪心算法
455. 分发饼干假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
示例 1:
输入: g = [1,2,3], s = [1,1]输出: 1解释:你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。所以你应该输出1。
1234567891011121314int findContentChildren(vector<int>& g, vector<int>& s) { sort(g.begin(),g.end()); sort(s.begin(),s.end()); int slen = s.size(),glen = ...
实模式与保护模式
x86从计算机的历史谈起
远古时期的程序开发 : 直接操作物理内存
CPU 指令的操作数直接使用实地址( 实际内存地址 )
程序员拥有绝对的权利( 利用 CPU 指哪打哪 )
绝对的权利带来的问题
难以重定位程序每次都需要同样地址的内存执行,某一程序能在A电脑上运行,到了B电脑上就不一定能运行了(B电脑内存不一定够)
给多道程序设计带来障碍不管内存多大,但凡一个字节被其它程序占用都无法执行,对于A程序和外设备交互,不再需要处理机了,这个时候处理机去调度B程序,如果A程序和B程序有重合那么问题就很大了
CPU 历史的里程碑- 8086
地址线宽度为 20 位 , 可访问 1M(2^20)内存空间
引入 [ 段地址 : 偏移地址 ] 的内存访问方式8086的段寄存器和通用寄存器为16位单个寄存器寻址最多访问64K 的内存空间需要两个寄存器配合 , 完成所有内存空间的访问
这个时候重定位就非常简单了,只需要写死偏移地址,如果有冲突就修改段基址即可
深入解析 [ 段地址 : 偏移地址 ]- 硬件所做的工作 段地址左移4 位 , 构成20 位的基地址( 起始地址 ) ...
MBR加载LOADER
辅助函数字符串打印print(es:bp)先前在实现一个最简单的FYOS中打印字符串是通过10号中断每次打印1个字符不断循环实现完整打印,而不是一次性全部打印出
BIOS 中的字符串打印- 指定打印参数( AX = 0x1301, BX = 0x0007 )- 指定字符串的内存地址( ES:BP = 串地址 )- 指定字符串的长度( CX = 串长度 )- 中断调用( int 0x10)
1234567891011121314151617181920------------------------------------------------------------------ INT 0x10功能0x13 -------------------------------------------------------------- 描述: 以电传打字机的方式显示字符串 接受参数: AH 0x13 AL 显示模式 BH 视频页 BL ...
BIOS
BIOS- Base Input&Output System
- BIOS 是计算机上电后第一个运行的程序
- BIOS 首先检测硬件状态,检测通过后立即进行硬件初始化
- BIOS 会在内存中建立中断向量表( 提供硬件访问的方法,比如int 10h中断向量是BIOS提供的中断例程)
- BIOS 最后将控制权交由主引导程序执行
注意:BIOS 不是软件( Software ) , 而是固件( Firmware ) !
固件是固化于硬件中的程序 ,在硬件出厂前已经烧写固定。
系统启动流程:
BIOS运行机制
BIOS 存储于 ROM(只读内存,硬盘) 中 , 地址映射为 0xF0000 - 0xFFFFF ( 实地址 )
BIOS的入口地址为 : 0xFFFF0
硬件电路的特殊设计使得 :开机后 , CPU 从 0xFFFF0 处开始执行
BIOS不被谁加载执行,通过硬件设计后,CPU直接从BIOS入口地址开始执行
BIOS 最后的使命
按照用户设置扫描各个存储介质( 光驱,软驱,u盘,等 )
发现主引导区后 , 将主引导区中的主引导程序载入内存
主引导程 ...
利用FAT12文件系统加载指定程序
主引导程序格式化(FAT12)在文章BIOS中编写了一个最简单的主引导程序boot.bin(第一句org 7c00,最后一句db 0x55,db 0xaa),并且将二进制代码boot.bin输入到了虚拟软盘的起始位置并且成功运行了
主引导程序位于0扇区,以0x55aa结束标记,大小不可以超过512字节512字节的大小代码量成为了一个限制,那么应该如何突破限制?
突破思路如下,主引导程序:
首先主引导程序本身要加载到内存中,并且完成最基本的初始化工作
然后主引导程序从存储介质中找到一段新程序并且将新程序加载到内存中
主引导程序将控制权交由新加载的程序执行
问题就变为了 主引导程序如何加载存储介质中的其它程序?
文件系统:存储介质上组织文件数据的方法( 数据组织的方式 )
FAT12文件格式如上,引导扇区里有主引导程序,而FAT1和FAT2并无差别,可以相互备份
文件系统示例
FAT12 是 DOS 时代的早期文件系统
FAT12 结构非常简单,一直沿用于软盘
FAT12 的基本组织单位• 字节( Byte ) : 基本数据单位• 扇区( Sector ) : 磁盘中的最 ...
前缀和
前缀和其实我们很早之前就了解过的,我们求数列的和时,Sn = a1+a2+a3+…an; 此时Sn就是数列的前 n 项和。例 S5 = a1 + a2 + a3 + a4 + a5; S2 = a1 + a2。所以我们完全可以通过 S5-S2 得到 a3+a4+a5 的值,这个过程就和我们做题用到的前缀和思想类似。我们的前缀和数组里保存的就是前 n 项的和。见下图
**我们通过前缀和数组保存前 n 位的和(不包含下标n自身这位)**,presum[1]保存的就是 nums 数组中前 1 位的和,也就是 presum[1] = nums[0], presum[2] = nums[0] + nums[1] = presum[1] + nums[1]. 依次类推,所以我们通过前缀和数组可以轻松得到每个区间的和。
12345678910111213141516class Solution {public: int pivotIndex(vector<int>& nums) { int len = nums.size(); ...
lambda表达式
用法简介c++11: 也是一种可调用对象。lambda表达式,它定义了一个匿名函数,并且可以捕获定范围内的变量。
1234auto f = [](int a)->int{ return a + 1;};cout << f(10) << endl;
特点:
a)是个匿名函数,也可以理解为“可调用的代码单元”,或者理解成未命名的内联函数。
b)它也有一个返回类型,一个参数列表,一个函数体
c)与函数不同的是,lambda表达式可以在函数内部定义,这个是常规函数做不到的:
格式:[捕捉列表] (参数列表) ->返回类型函数体};
这是一个返回类型后置这种语法( lambda表达式的返回类型后置是必须的,这个语法就这么规定) ;因为很多时候lambda表达式返回值特别明显,所以允许lambda表达式返回类型省略,编译器可以自动推导; 但是如果编译器推断不出来的时候需要我们自定义返回类型,否则就会报错。
1.没有参数的时候,参数列表可以省略,甚至()也能省略,所以如下格式都合法
1234auto f1 = []( ...
二叉树
树的遍历144. 二叉树的前序遍历(迭代)根左右
借助栈实现,注意空节点不应该入栈,每次取出栈顶元素就是先序结果,注意每一次循环中应该让左孩子位于栈顶,于是呢就先压入右孩子,再压入左孩子
1234567891011121314vector<int> preorderTraversal(TreeNode* root) { stack<TreeNode*>st; vector<int>results; if(root == nullptr)return results; st.push(root); while(!st.empty()){ TreeNode* cur = st.top(); st.pop(); results.push_back(cur->val); //根,每次取出的是栈顶元素根 if(cur->right != nullptr)st.push(cur->right); //先入右孩子,右孩子在栈底部 ...
BFS广度优先
752. 打开转盘锁
方法一:BFS
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253class Solution {public: string plusOne(string s,int i){ if(s[i] == '9')s[i] = '0'; else s[i] = s[i] + 1; return s; } string minusOne(string s,int i){ if(s[i] == '0')s[i] = '9'; else s[i] = s[i] - 1; return s; } set<string>visited; int openLock(vector< ...
单调栈
z
栈排序单调栈单调栈是一种和单调队列类似的数据结构。单调队列主要用于解决滑动窗口问题,单调栈则主要用于 解决NGE问题(Next Greater Element),也就是,对序列中每个元素,找到下一个比它大的元素。(当然,“下一个”可以换成“上一个”,“比它大”也可以换成“比他小”,原理不变。)
这比单调队列还简单一点。我们维护一个栈,表示“待确定NGE的元素”,然后遍历序列。当我们碰上一个新元素,我们知道,越靠近栈顶的元素离新元素位置越近。所以不断比较新元素与栈顶,如果新元素比栈顶大,则可断定新元素就是栈顶的NGE,于是弹出栈顶并继续比较。直到新元素不比栈顶大,再将新元素压入栈。显然,这样形成的栈是单调递减的。
42. 接雨水
方法一:按行求
依次遍历每一行,思路比较简单,理解容易除了超时之外并无明显缺点
1234567891011121314151617181920class Solution {public: int trap(vector<int>& height) { int maxh = 0; f ...