2022-04-08 14:08:00
交叉编译一般是指在一个平台上生成另一个平台上的可执行代码,因为有一些目标平台性能很弱,编译需要花费很长的时间,所以需要在性能较高的平台上通过交叉编译来得到目标程序。
在golang和rust中交叉编译都是很容易实现的。
golang交叉编译一般不需要额外的工具,只需要在golang编译时指定GOOS
(操作系统)和GOARCH
(CPU架构)即可。
可以使用go tool dist list
来查看所有支持的目标平台。
但是如果代码中使用了cgo,那么通常还需要指定一个CC
(一般为gcc)来进行编译。
如果目标平台使用glibc库,可以快捷的使用xgo来进行交叉编译。
但是有些目标平台是使用的是musl库,或者是使用其他版本的C库,就需要手动安装交叉编译工具链了。
通过CC指定musl-gcc
之后,编译出来的程序就可以在musl库的目标平台下运行了,但是其他版本的C库又不行了,这里要引入一个新的概念,叫做静态编译
,即直接将用到的库链接到目标程序中,这样就不在依赖其他的库了。
二进制程序依赖的库可以通过ldd file
查看。
在golang中,在ldflags
中加入--extldflags '-static -fpic'
参数即可开启静态编译,这时使用musl编译出来的二进制文件就可以在所有的目标平台运行了,无论使用的是什么C库。
为什么不直接使用glibc来进行静态编译呢?
直接使用glibc编译出来的二进制文件用ldd查看也是没有依赖的,但是在musl库系统下就是无法运行,我也不知道为什么。
rust有专门用于交叉编译的库:cross,使用cross build
命令直接指定target他就可以工作了。
如果需要手动交叉编译,在rust中进行交叉编译通常比golang中多一步,需要使用rustup target add
来添加目标target,同样的所有目标target都可以通过rustup target list
来查看。
然后就是和golang一样需要一个gcc,但是有少数时候又不需要,例如在x86_64-unknown-linux-gnu
上编译目标平台为x86_64-unknown-linux-musl
的hello-world
程序就不需要安装额外的musl-gcc
,至于为什么这样,我也不知道。
另外Rust可能还需要在.cargo/config
中添加一个[target.'x86_64-unknown-linux-gnu'.linker = "xxx"]
来指定使用的gcc,编译时也需要加入--target host
来指定目标平台。
网上很多文章说需要
rustup toolchain install
,其实是错误的(我认为)
2022-03-23 14:08:00
给定整数 n
和 k
,返回 [1, n]
中字典序第 k
小的数字。
示例 1:
1 |
输入: n = 13, k = 2 |
示例 2:
1 |
输入: n = 1, k = 1 |
提示:
1 <= k <= n <= 109
通过观察字典序的排列可以发现以下规律:
要找到在[1,n]中第k小的数字,我们肯定需要从以i作为前缀的开始数,首先需要计算出以i为前缀的个数,以i为前缀的个数即:以i+1为前缀的最小值-以i为前缀的最小值,且这些值都必须小于n。
找到以i为前缀的个数count后,有两种情况:
1 |
impl Solution { |
2022-03-22 14:08:00
给你一个有 n
个服务器的计算机网络,服务器编号为 0
到 n - 1
。同时给你一个二维整数数组 edges
,其中 edges[i] = [ui, vi]
表示服务器 ui
和 vi
之间有一条信息线路,在 一秒 内它们之间可以传输 任意 数目的信息。再给你一个长度为 n
且下标从 0 开始的整数数组 patience
。
题目保证所有服务器都是 相通 的,也就是说一个信息从任意服务器出发,都可以通过这些信息线路直接或间接地到达任何其他服务器。
编号为 0
的服务器是 主 服务器,其他服务器为 数据 服务器。每个数据服务器都要向主服务器发送信息,并等待回复。信息在服务器之间按 最优 线路传输,也就是说每个信息都会以 最少时间 到达主服务器。主服务器会处理 所有 新到达的信息并 立即 按照每条信息来时的路线 反方向 发送回复信息。
在 0
秒的开始,所有数据服务器都会发送各自需要处理的信息。从第 1
秒开始,每 一秒最 开始 时,每个数据服务器都会检查它是否收到了主服务器的回复信息(包括新发出信息的回复信息):
i
每 patience[i]
秒都会重发一条信息,也就是说,数据服务器 i
在上一次发送信息给主服务器后的 patience[i]
秒 后 会重发一条信息给主服务器。当没有任何信息在线路上传输或者到达某服务器时,该计算机网络变为 空闲 状态。
请返回计算机网络变为 空闲 状态的 最早秒数 。
示例 1:
1 |
输入:edges = [[0,1],[1,2]], patience = [0,2,1] |
示例 2:
1 |
输入:edges = [[0,1],[0,2],[1,2]], patience = [0,10,10] |
提示:
n == patience.length
2 <= n <= 105
patience[0] == 0
1 <= i < n
,满足 1 <= patience[i] <= 105
1 <= edges.length <= min(105, n * (n - 1) / 2)
edges[i].length == 2
0 <= ui, vi < n
ui != vi
这里每个服务器最后变的空闲的时间都是相互独立的,所以我们算出每一个服务器接收最后一条消息的时间然后取最大的那一个就行了。
要计算这个的时间,首先肯定是需要计算每个服务器到服务器0的最短距离,这里刚开始使用的是迪杰斯特拉,但是提交之后超时了,然后观察到所有服务器的距离都是1,所以直接BFS就可以得到距离。
然后考虑怎么计算每个服务器的接受到最后一条消息的时间,接受最后一条消息的时间=发出最后一条消息的时间+2*服务器距离+1,所以最后需要计算的是最后一条消息发出的时间,如果距离的话,那么最后一条消息就是第一条消息,否则:
在停止发消息前,经历了的时间,再此期间则会发送条消息,那么最后一条消息的时间就是:
1 |
use std::collections::VecDeque; |
2022-03-20 14:08:00
大部分的hexo主题自带的数学公式支持都是使用mathjax,但是这个插件的支持不是很好,有很多的公式无法正常显示。在网上搜索一番后,似乎是因为和markdown语法的冲突,发现很多人都推荐使用hexo-renderer-markdown-it-plus,它使用katex来支持数学公式的渲染但是安装之后又发现另一个问题,公式无法换行,在摸索了很长时间之后,最终发现是katex的版本的问题,然后找到了另一个渲染的库:@upupming/hexo-renderer-markdown-it-plus。现将使用的过程记录如下:
首先需要替换默认的markdown渲染器:
1 |
npm un hexo-renderer-marked --save |
然后需要引入katex的样式文件,这里要注意官方的文档里用的还是0.9.0的老版本同样不支持换行,所以需要改成0.10.2的版本,这里使用字节的cdn:
1 |
<link href="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/KaTeX/0.10.2/katex.min.css" rel="stylesheet"> |
现在就可以随意的书写数学公式了,比如:
这里可能还会有一个问题就是,如果公式很长但是屏幕又很窄,公式就有可能超出屏幕,让主题变得很难看,可以添加一个css来改进这个问题:
1 |
.katex-display { |
2022-03-11 14:08:00
给你一个数组 nums
,我们可以将它按一个非负整数 k
进行轮调,这样可以使数组变为 [nums[k], nums[k + 1], ... nums[nums.length - 1], nums[0], nums[1], ..., nums[k-1]]
的形式。此后,任何值小于或等于其索引的项都可以记作一分。
nums = [2,4,1,3,0]
,我们按 k = 2
进行轮调后,它将变成 [1,3,0,2,4]
。这将记为 3
分,因为 1 > 0
[不计分]、3 > 1
[不计分]、0 <= 2
[计 1 分]、2 <= 3
[计 1 分],4 <= 4
[计 1 分]。在所有可能的轮调中,返回我们所能得到的最高分数对应的轮调下标 k
。如果有多个答案,返回满足条件的最小的下标 k
。
示例 1:
1 |
输入:nums = [2,3,1,4,0] |
示例 2:
1 |
输入:nums = [1,3,0,2,4] |
提示:
1 <= nums.length <= 10^5
0 <= nums[i] < nums.length
首先的思路当然是暴力求解,直接遍历K在0到nums.length
这个范围内的所有得分,然后取得分最高的k值(若有多个取较小的k)即可,这样写思路很清晰代码也是比较简单的,但是这道题目的数据量是,这样做的时间复杂度是,肯定是会超时的,所以需要去优化。
首先我们将问题转化,先求出数组中每个值要取得得分时k的范围,假设下标为i,则需要:
最终得到k的范围为:
我们就可以在的时间内求得每项可以得分的k的区间,这样问题就转换为了求k取多少时落在这些区间里最多(k取较小值)?
然后我们可以这样来求解:先初始化一个长度为n,值为0的数组,然后对于上述的每个区间,将这个数组下标落在区间里的值加一,遍历完之后值最大的那个下标即为得分最高的k值。但是这样做的时间复杂度依然为,因为有n+个区间,每个区间的长度的数量级也为n,所以这里需要引入一个算法:差分数组
差分数组就是专门对数组的某个区间进行相同的操作,且时间复杂度为的一个算法,他的本质其实是前缀和的逆操作。步骤如下:
首先求对应数组的差分数组:
就本题来说初始的数组是,那对应的差分数组仍为;当我们需要对某个区间进行操作时只需要对端点处进行修改,如对都+1则只需要
即对左侧端点进行这个修改,对右侧的右边一个进行逆修改。
然后是差分数组如何还原,进行前缀和运算就行了,因为前缀和是对数组前i项的累加,对左侧端点的修改就影响了后面的所有值,而对右侧端点的右边一个逆修改相当于消除了对之后的影响,于是就变成了对的操作,且这里所有的操作都是的。
然后使用这种算法再对上面的先初始化一个长度为n,值为0的数组,然后对于上述的每个区间,将这个数组下标落在区间里的值加一,遍历完之后值最大的那个下标即为得分最高的k值
问题求解就很简单了。
1 |
impl Solution { |
2022-02-17 14:08:00
先看看官方的定义:
A crate is a binary or library. The crate root is a source file that the Rust compiler starts from and makes up the root module of your crate (we’ll explain modules in depth in the “Defining Modules to Control Scope and Privacy” section). A package is one or more crates that provide a set of functionality. A package contains a Cargo.toml file that describes how to build those crates.
crate是rust中的最小编译单元,也就是说rust是按照一个一个的crate来编译的,每个crate都有一个入口文件,可以是下面三种情况:
而mod则更像是C++中的命名空间,以下几种情况都可以作为一个根mod:
mod是可以嵌套的,它是一个树形结构,要想使用mod,则必须在某个入口文件中声明mod(其实rust就是以这个mod名称寻找文件进行了替换),而子mod则可以在它的父mod中进行声明,然后在要使用的地方有以下几种使用方式:
文件:
1 |
├─src |
1 |
// test_mod/child.rs |