WAP 校招面试算法题。
Round 0
Round 1
Round 2
Strobogrammatic Number I, II, III
Round 3
- 勾股定理
grep,find
Round 4
- Small Chat
WAP 校招面试算法题。
Strobogrammatic Number I, II, III
grep, find腾讯互娱校招面试算法题。
这个也是 LeetCode 原题:Integer Break
给定 $m\in N$,
$\max x_1\cdot x_2\dots x_{n-1}\cdot x_n$
s.t. $x_1+x_2+…+x_n = m$ and $x_i \in N $.
(面试官给的题目里 $m = 25$)
下面我们介绍两种解法,一种是使用动态规划的编程解,另一种是直接手算出答案的数学解。
我们使用 dp(m) 表示将整数 m 进行如上拆分后所能得到的最大乘积。那么我们要的结果就是 dp(25).
如何计算 dp(m) 呢?对于一般的情况,我们直接根据所拆分出来的第一个整数进行动态规划:
dp(m)= max{i * dp(m-i)} 其中,i \in {1,...,m}
这里为了便于计算我们将边界条件设为 dp(0) = 1
上面这个算法的复杂度是 O(m^2) :首先我们需要计算 dp(1),...,dp(m) 这 m 个值,然后在计算每个值dp(m_0)的时候我们需要进行一个 O(m_0) 层的循环。
首先我们假设分成的份数 n 是固定的,那么根据 均值不等式我们有
$\prod_{i=1}^n x_i \le (\frac{\sum_{i=1}^n x_i}{n}) ^ n = (\frac{m}{n}) ^ n$
(几何平均值小于等于算术平均值)
上式取等的条件为各 $x_i$ 均相等。
也就是说,对于给定的 n ,我们要使得各份尽量均匀的情况下乘积最大。
下面我们考虑最优的 n 的取值。我们令 $g(n) = (\frac{m}{n})^n$, 于是只需要求 $g(n)$ 的最大值。
求导,$g’(n)=((\frac{m}{n})^n)’=(e^{n\ln(m/n)})’=e^{n\ln(m/n)}\cdot (n\ln(\frac{m}{n}))’$
因为 $(n\ln(\frac{m}{n}))’=ln(\frac{m}{n}) + n\cdot(ln(\frac{m}{n})’)=ln(\frac{m}{n}) + n \cdot \frac{n}{m} \cdot (-\frac{m}{n^2}) = ln(\frac{m}{n}) - 1$
从而 $g’(n) > 0\Leftrightarrow ln(\frac{m}{n})-1 > 0 \Leftrightarrow ln(\frac{m}{n}) > 1\Leftrightarrow \frac{m}{n} > e \Leftrightarrow n < \frac{m}{e}$
也就是说,$g(n)$ 在 $(1, \frac{m}{e})$ 递增,在 $(\frac{m}{e}, +\infty)$ 递减。
所以 $g(n)$ 在 $n=\frac{m}{e}$ 时取最大值,也就是说对于给定的数 $m$, 我们希望分成 $\frac{m}{e}$ 份,也就是说我们希望每份分成的数值是 $e$. 这里的 $e=2.71828$.
由于要求分成整数,所以我们应该分成尽量多的 3 和最多两个 2(因为我们可以把3个2变成2个3)
具体来讲,如果 m % 3 == 0,那就是 m / 3 个 3; m % 3 == 2 就是 m / 3 个 3 和 1 个 2;m % 3 == 1, 我们把多出来的 1 和它前面的那个 3 放一起拆成两个 2(2 * 2 > 1 * 3), 就是 (m / 3 - 1) 个 3 和 2 个 2.
具体到 25,就是 25 = 3 * 7 + 2 * 2,最大的积为 $3^7\times 2^2$.
$\cdot$
面试中遇到的其他问题包括:
Package management on Ubuntu using apt/dpkg
Linux Standard Base.
1 | lsb_release -a |
1 | E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable) |
1 | Reading package lists... Error! |
1 | sudo apt-get update |
1 | 2 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. |
clean: clean clears out the local repository of retrieved package files. It removes everything but the lock file from /var/cache/apt/archives/ and /var/cache/apt/archives/partial/. When APT is used as a dselect(1) method, clean is run automatically. Those who do not use dselect will likely want to run apt-get clean from time to time to free up disk space.autoclean: Like clean, autoclean clears out the local repository of retrieved package files. The difference is that it only removes package files that can no longer be downloaded, and are largely useless. This allows a cache to be maintained over a long period without it growing out of control. The configuration option APT::Clean-Installed will prevent installed packages from being erased if it is set to off.autoremove: is used to remove packages that were automatically installed to satisfy dependencies for some package and that are no more needed.1 | 29 not fully installed or removed. |
1 | sudo apt install -f |
Searches for packages that have been installed only partially on your system. dpkg will suggest what to do with them to get them working.
1 | sudo dpkg -C |
1 | The following packages have been unpacked but not yet configured. |
1 | sudo dpkg --configure -a |
1 | dpkg-query: package 'ibus-table' is not installed |
1 | sudo apt install ibus-table |
一枚硬币, 扔出 H 的概率为 $p$, T 的概率为 $q$, 计算首次扔出 $T\underbrace{H\dots H}_{k}$ 所需投掷次数的数学期望。
我们先来考虑 $\underbrace{H\dots H}_{k}$ 这样简单后的情形,然后试图将其推广到任意模式的一般情况。
记 随机变量 $X_k$ 为 首次投掷出 $\underbrace{H\dots H}_{k}$ 所需的次数。
设我们要求的数学期望为 $e$, 则有
$$
e = q (1+e) + p q (2+e) + p p q (3+e) + p^{k-1} q (k+e) + p^k k
$$
这是对前 $k$ 位可能出现的模式进行分类讨论得到的。
记 $S=1+2p+3p^2+\dots+kp^{k-1}$, 可得 $S=1/q((1-p^k)/q-kp^k)$.
1 | e |
从而
$$e = 1/q (1/p ^k - 1)$$
这与我们上面的结果是吻合的。
推广:首次投掷出 HTHHT
$$e = q(1+e) + pp(2+e) + pqq(3+e) + pqpq(4+e) + pqppp(5+e) + pqppq 5$$
1 | X_k = (X_{k-1} + 1)\cdot p + (X_{k-1} + 1 + X_k)\cdot q |
1 | X_k = 1/p X_{k-1} + 1/p |
1 | X_k = 1/q (1/p ^k - 1) |
而递推式的由来在于
1 | Pr(X_k = n) |
也就是
1 | X_k = p (X_{k-1}+1) + q (X_{k-1}+X_{k}+1) |
这是由于对于随机变量 X, Y, Z, 若 Z=X+Y,则
1 | Pr(Z=n) = \sum_m [Pr(X=m) Pr(Y=n-m)] |
递推法可以使得我们顺便求出所有的 X_k
推广:首次投掷出 HTHHT
If f(x) is the generating function of the probability p_n of the ending after n tosses
1 | f(x) = \sum_n p_n x^n |
Consider the following toss strings, probabilities, and terms
1 | T q qx |
We get the generating function of the probability of ending after n tosses to be
1 | f(x) |
1 | f'(1) = \sum p_n n = |
推广:首次投掷出 HTHHT
1 | T qx |
1 | f(x) |
10000桶酒,其中1桶是毒酒;48小时后要举行酒会;毒酒喝下去会在之后的第23-24小时内毒死人。
国王决定用囚犯来试酒,不介意囚犯死多少,只要求用最少的囚犯来测试出哪一桶是毒酒。
问最少需要多少囚犯才能保证找出毒酒?
然后大概可以这样操作,假设有 $t$ 个时间点可以喝酒。
给这 $n$ 瓶酒用一个 $m$ 维的向量编号,每一维的取值范围是 $(0, 1, …, t)$,这里 $m = \lceil log_{t+1}(n) \rceil$。
这样每一维对应一个人吧,然后在 $t_1$ 时让 $m_1$ 这个人喝下所有编号在第 $m_1$ 维的分量是 $t_1$ 的酒。
根据每一维对应的人的死亡时间确定这一维的分量(如果没死就是 0,如果在 $t_1$ 对应的时间死亡就是 $t_1$)。
综合所有人的死亡时间确定所有维的分量。
再把这个向量换算回原来的编号。
Basic usage of Bash.
It executes the content of the file in the current shell.
synonym: . (period).
1 | echo $- |
CTRL+Z, fg~/.bash_history, !!cp file{,.bak}if [ "${-#*i}" != "$-" ] checking if your shell is interactive or not
$*: equivalent to $1c$2c...$@: equivalent to $1 $2 …$#: number of position parameters in decimal $?: exit status of the most recently executed foreground pipeline$-: the current option flags as specified upon invocation$$: the process ID of the shell$!: the process ID of the job most recently placed into background$0: the name of the shell or shell script $_: the absolution path name used to invoke the shellA double dash (--) is used in bash built-in commands and many other commands to signify the end of command options, after which only positional parameters are accepted.
Example use: lets say you want to grep a file for the string -v - normally -v will be considered the option to reverse the matching meaning (only show lines that do not match), but with -- you can grep for string -v like this:
1 | grep -- -v file |
[ ] vs [[ ]] are test operators
[[ handles empty strings and strings with whitespace more intuitively.&& and || operators for boolean tests and < and > for string comparisons. =~ operator for doing regular expression matches. 1 | if [ -f "$FILE" ] |
1 | -z字串 字串长度伪则为真。 |
1 | -e文件名 如果文件存在则为真。 |
$() is command substitution
1 | $ echo "my hostname is: $(hostname)" |
$(( )) is arithmetic expansion
1 | $ echo "$(( 5 + 5 ))" |
${ } This is used to refer to variables and avoid confusion over their name.
1 | $ v="hello" |
Also, it is used to reference array elements:
1 | $ declare -A my_arr |
( ) and { } are also used as grouping commands
( ) runs in a subshell:
1 | $ v=5 |
Whereas { list, } does not:
1 | $ v=5 |
${value:-word}: 当变量未定义或者值为空时,返回值为word的内容,否则返回变量的值. ${value:=word}: 与前者类似,只是若变量未定义或者值为空时,在返回word的值的同时将word赋值给value${value:?message}: 若变量以赋值的话,正常替换.否则将消息message送到标准错误输出(若此替换出现在Shell程序中,那么该程序将终止运行) ${value:+word}: 若变量以赋值的话,其值才用word替换,否则不进行任何替换 ${value:offset}, ${value:offset:length}: 从变量中提取子串,这里offset和length可以是算术表达式. ${#value}: 变量的字符个数 ${value#pattern}, ${value##pattern}: 去掉value中与pattern相匹配的部分,条件是value的开头与pattern相匹配 #与##的区别在于一个是最短匹配模式,一个是最长匹配模式. ${value%pattern}, ${value%%pattern}: 于(7)类似,只是是从value的尾部于pattern相匹配,%与%%的区别与#与##一样 ${value/pattern/string}, ${value//pattern/string}: 进行变量内容的替换,把与pattern匹配的部分替换为string的内容,/与//的区别与上同1 | INFORMIX_HOME="${INFORMIX_HOME%/}" # Strip the trailing / (if exists) |
注意: 上述条件变量替换中,除(2)外,其余均不影响变量本身的值
1 | set -euxo pipefail |
-x: print commands and their arguments as they are executed-e: equivalent to cmd1 && cmd2 && cmd3-u: The shell prints a message to stderr when it tries to expand a variable that is not set. Also it immediately exits. -o option-name: set the variable corresponding to option-name.+o option-name: using + rather than - will cause the option to be turned off.-o pipefail: Pipelines fail on the first command which fails instead of dying later on down the pipeline. This is especially good when cmd3 is a command that always succeeds (like echo)-f: disable filename expansion (globbing) upon seeing *, ?, etc.1 | -s stdin Read commands from stdin |
1 | #!/bin/sh |
1 | ./abc/test.sh |
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 得到shell脚本文件所在完整路径(绝对路径)及文件名(无论source,sh,.三种调用方式),且不改变shell的当前目录。
Basic usage of Docker.
1 | sudo docker build -t tc-informix . |
1 | sudo docker images |
1 | sudo docker rmi $(sudo docker images -q -f dangling=true) |
1 | sudo docker run -it --rm ubuntu:14.04 bash |
1 | sudo docker ps |
1 | docker rm $(docker ps -a -q) |
1 | sudo docker stop d457395b35e2 |
1 | sudo docker attach nostalgic_hypatia |
1 | sudo docker logs -t iif_developer_edition |
日志文件位于 var/lib/docker/containers/<container_id>,文件名为 <container_id>-json.log
1 | touch Dockerfile |
1 | FROM nginx |
Docker has a default entrypoint which is /bin/sh -c but does not have a default command.
When you run docker like this: docker run -i -t ubuntu bash the entrypoint is the default /bin/sh -c, the image is ubuntu and the command is bash.
The command is run via the entrypoint. i.e., the actual thing that gets executed is /bin/sh -c bash. This allowed docker to implement RUN quickly by relying on the shell’s parser. Later on, people asked to be able to customize this so ENTRYPOINT and -entrypoint has been introduced.
An other example would be to have any cli as entrypoint. For instance, if you have a redis image, instead of running docker run redisimg redis -H something -u toto get key, you can simply have ENTRYPOINT ["redis", "-H", "something", "-u", "toto"] and then run like this for the same result: docker run redisimg get key.
When the operator executes docker run --privileged, Docker will enable to access to all devices on the host as well as set some configuration in AppArmor or SELinux to allow the container nearly all the same access to the host as processes running outside containers on the host.
1 | sudo apt-get install docker-engine |
1 | Cannot connect to the Docker daemon. Is the docker daemon running on this host? |
1 | sudo service docker start |
1 | sudo docker pull ubuntu:14.04 |
1 | sudo docker pull nginx |
1 | echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html |
1 | sudo docker diff webserver |
1 | docker build -t nginx:v3 . |
因此,COPY 这类指令中的源文件的路径都是相对路径。这也是初学者经常会问的为什么 COPY ../package.json /app 或者 COPY /opt/xxxx /app 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。
1 | sudo docker export 7691a814370e > ubuntu.tar |
Basic usage of git.
First, create a branch named tmp and commit your tmp work there.
1 | git checkout -b tmp |
Then, push local tmp branch to remote tmp branch.
1 | git push origin tmp |
You can restore the state of your local workspace by:
1 | git checkout master |
Fetch the tmp remote branch locally:
1 | git fetch origin tmp:tmp |
Merge content of tmp branch into your main branch:
1 | git merge tmp |
Reset soft and restore so that the last commit is reverted:
1 | git reset --soft HEAD~1 |
Delete the local and remote tmp branch:
1 | git branch -D tmp |
Stash your unstaged work to make your working dir clean:
1 | git stash |
Fetch remote branch and merge:
1 | git pull origin main |
Git stash pop:
1 | git stash pop |
Alternatively, you can use the --autostash flag to handle this entire workflow in a single command:
1 | git pull origin main --autostash |
https://gist.github.com/patik/b8a9dc5cd356f9f6f980
1 | git reset --soft HEAD~3 |
1 | git push origin +master |
1 | git log --author=songzy |
1 | git reset <file> |
Remove the specified file from the staging area, but leave the working directory unchanged.
1 | git reset |
Reset the staging area to match the most recent commit, but leave the working directory unchanged.
1 | git reset --hard |
Reset the staging area and the working directory to match the most recent commit.
1 | git reset <commit> |
Move the current branch tip backward to
1 | git reset --hard <commit> |
Move the current branch tip backward to
Whereas reverting is designed to safely undo a public commit, git reset is designed to undo local changes.
1 | git add foo.py |
The git reset HEAD~2 command moves the current branch backward by two commits.
1 | # Add the remote, call it "upstream": |
1 | git show-branch -a |
Show branches and their commits
1 | git branch <branch> |
Create a new branch called
1 | git branch -d <branch> |
Delete the specified branch.
1 | git branch -D <branch> |
Force delete the specified branch, even if it has unmerged changes.
1 | git branch -m <branch> |
Rename the current branch to <branch>.
1 | git checkout $branch2 |
Merge branch1 into branch2.
1 | warning: refname 'HEAD' is ambiguous. |
1 | git branch -m HEAD temp |
Give up the current modification and go back to the last commit
1 | git checkout -- . |
1 | git log --oneline |
You can find the ID of the revision you want to see.
1 | git checkout a1e8fb5 |
Nothing you do in here will be saved in your repository.
1 | git checkout a1e8fb5 hello.py |
Unlike checking out a commit, this does affect the current state of your project.
1 | git status |
1 | git checkout source |
1 | git stash |
1 | git clean -n |
This will show you which files are going to be removed without actually doing it.
1 | git clean -f |
Remove untracked files from the current directory.
1 | git clean -f <path> |
Remove untracked files, but limit the operation to the specified path.
1 | git clean -df |
Remove untracked files and untracked directories from the current directory.
1 | git clean -xf |
Remove untracked files from the current directory as well as any files that Git usually ignores.
If you clone a repository, the default branch you have is whatever the remote’s HEAD points to (HEAD is actually a symbolic ref that points to a branch name).
A symbolic ref is a regular file that stores a string that begins with ref: refs/. For example, your .git/HEAD is a regular file whose contents is ref: refs/heads/master.
HEAD@{1} is always last value of HEAD, ORIG_HEAD is last value of HEAD before dangerous operation.
1 | git commit --amend |
Combine the staged changes with the previous commit and replace the previous commit with the resulting snapshot.
1 | git commit -a |
Commit all your local changes. (like git add . followed by git commit)
1 | vi ~/.gitconfig |
1 | git config --global user.email "your_email@example.com" |
1 | git diff filename |
1 | git fetch |
Fetch all of the branches from the repository. This also downloads all of the required commits and files from the other repository.
1 | git checkout master |
1 | error: RPC failed; result=18, HTTP code = 0 |
1 | git fetch origin master |
1 | $ git format-patch -o ./patches -2 |
1 | git am ./patches/* |
Check all the change paths to file Predictor.java.
1 | git log --follow -p Predictor.java |
1 | git merge --squash <branch_name> |
將另一個 branch 的 commit 合併為一筆,特別適合需要做實驗的 fixes bug 或 new feature,最後只留結果。合併完不會幫你先 commit。
1 | git pull <远程主机名> <远程分支名>:<本地分支名> |
如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
Here.
1 | ssh: connect to host github.com port 22: Connection refused |
1 | vi ~/.ssh/config |
1 | git push <远程主机名> <本地分支名>:<远程分支名> |
1 | git push origin HEAD:master |
See the commits tab(rather than project tab). It is all there.
1 | ssh -v -T songzy12@git.tsinghuax.org |
IP filtered, move to your lab.
1 | fatal: Could not read from remote repository. |
Server down.
1 | git remote set-url origin git@github.com:songzy12/certificate_predictor.git |
1 | git revert <commit> |
Generate a new commit that undoes all of the changes introduced in <commit>, then apply it to the current branch.
1 | git commit -m "Make some changes that will be undone" |
1 | git rm -r --cached ".\source\_posts\Git Shell.lnk" |
The git rm command will allows you to remote a file from git control. The –cached option to git remove allows you to leave it on your hard drive.
1 | git stash |
The mode is taken from normal UNIX modes but is much less flexible – these three modes are the only ones that are valid for files (blobs) in Git (although other modes are used for directories and submodules).
The 6 digits show the file mode using the classical UNIX notations. First two digits show file type, the third one is about set-uid/set-gid/sticky bits, and you know the last three. 4\2\1 is just r\w\x.
1 | man 2 stat |
1 | S_IFLNK 0120000 symbolic link |
To ignore file mode changes:
1 | repo forall -c git config core.fileMode false |
Basic usage of tmux.
1 | vi ~/.tmux.conf |
1 | set -g mouse on |
session指的是按下tmux命令后 存在的连接便是session
1 | 创建session |
pane在window里,可以有N个pane,并且pane可以在不同的window里移动、合并、拆分
1 | 创建pane |
https://unix.stackexchange.com/questions/1045/getting-256-colors-to-work-in-tmux
1 | ❯ echo $TERM |
1 | vi ~/.tmux.conf |
Android RE.
arsc: Android package Resource file.
dex: dalvik executable
1 | apktool d RecentContest_beta.apk |
To remove Private access contests from the json result, just insert the following lines after :cond_1 of file JsonStringAnalysis.smali
1 | const-string v8, "Private" |
1 | java -jar testsign.jar RecentContest_beta.apk RecentContest_beta-signed.apk |
1 | Lcom/example/myapp/MyClass; |
.method keyword method-name parameters/return
1 | .method private delayedAnimationFrame(J)Z |