一、求一个无序数组中的第k大元素
(一)分治
(二)最小堆
(三)桶排序
二、关于排序的稳定性
概念:排序的稳定性是指如果在排序的序列中,存在前后相同的两个元素的话,排序前 和排序后他们的相对位置不发生变化
分类:堆排序、快速排序、希尔排序、直接选择排序不是稳定的排序算法,而基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法。
三、TCP和UDP的区别和应用场景
TCP(Transmission Control Protocol),又叫传输控制协议,UDP(User Datagram Protocol),又叫用户数据报协议,它们都是传输层的协议,但两者的机制不同,它们的区别如下:
特点 | TCP | UDP |
---|---|---|
连接性 | 面向连接 | 面向非连接 |
可靠性 | 可靠 | 不可靠 |
传输效率 | 慢 | 快 |
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保 证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
四、TCP三次握手
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
SYN:同步序列编号(Synchronize Sequence Numbers)
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手.
四次握手图如下,自己体会:
五、找出数组中出现了1|2|3次的数(类型题)
(一)找数组中唯一出现1次的数,其他都出现两次
解:显然答案为所有数的异或和
(二) 找出数组中唯一出现1次的数,其他都出现三次
解:比较容易想到的就是累加二进制每一位的1的个数,%3的结果即为解,但是这样的时间复杂度为O(nlogn),较慢,下面我来介绍一种比较好的方法。
这种方法即是不用拆开二进制再对每一位去计算贡献,我们用两个数,one和two。
one的某位二进制上为1时,代表该位出现1次,为0代表出现0或2次。(模3意义下)
two的某位二进制上为1时,代表该位出现2次,为0代表出现0或1次。(模3意义下)
那么
one=(one^a[i])&(~(two&a[i]))
two=(one^a[i])|(two&(~a[i]))
最后的one即所求,代码如下:
class Solution {
public:
int singleNumber(vector& nums) {
int n=nums.size();
int one=0,two=0;
for(int i=0;i
(三)找数组中两个出现1次的数,其他都出现两次
解:令第一个数为x,第二个数为y
易知,全部数的异或和为x^y=S
对于S的二进制上的任意一位1(一般取最低位或者最高位),我们可以把数组分成两个部分,使得x与y分别在不同的两个子数组中
A数组:a1,a1,a2,a2,a3,a3...x
B数组:b1,b1,b2,b2,b3,b3...y
x=A数组的异或和
y=B数组的异或和
(四)找数组中三个出现1次的数,其他都出现两次
解:令第一个数为x,第二个数为y,第三个数为z
易知,全部数的异或和为x^y^z=S
令f(t)为t的二进制只保留最后一个1的那个数,比如12(1110) f(12)=2(0010)
可推出:
1、S^x S^y S^z 两两不等且都大于0
2、f(S^x)^f(S^y)^f(S^z)>0
3、令 f(f(S^x)^f(S^y)^f(S^z))==1<
S=a[1]^a[2]^...^a[n]==x^y^z
T=f(f(S^a[1])^f(S^a[2])^...^f(S^a[n]))==f(f(S^x)^f(S^y)^f(S^z))==1<
找出了x,那么就转化为问题(二)了,搞定!
(五)找数组中唯一出现1次的数(微软面试题)要求空间复杂度O(1)
题:假设你有一个用1001个整数组成的数组,这些整数是任意排列的,但是你知道所有的整数都在1到1000(包括1000)之间。此外,除一个数字出现两次外,其他所有数字只出现一次。假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗?
在这里我为大家提供两种做法:
方法一(简单粗暴):
a[1]+a[2]+...a[n]-等差数列之和即为答案
方法二(面试加分):
解:因为限定了1~n,所有很显然这些数的异或和再^1^2^3...^n则为所求的答案。
(五)找数组中两个出现1次的数,条件同(四) 时间复杂度O(n),空间复杂度O(1)
解:在这里我为大家提供两种做法:
方法一(简单粗暴):
令x+y=a[1]+a[2]+...a[n]-等差数列之和
知道x+y与x^y的结果,那么枚举x就可以了
方法二(面试加分):
对于S的二进制上的任意一位1(一般取最低位或者最高位),我们可以把数组分成两个部分,使得x与y分别在不同的两个子数组中
A数组:a1,a2,a3...x,x
B数组:b1,b2,b3...y,y
x=A数组^(1~n中满足与S的该位相同的数)
y=B数组^(1~n中满足与S的该位不相同的数)
六、有一个很长二进制串,求出除以3的余数是多少,给出算法的时间复杂度。
1. 模拟大整数整除
过程 : 略
2. 统计二进制奇偶位上的 1 的个数
思路:因为二进制%3,可以想到直接二项式展开,2^x %3 = (3-1)^x %3 =... = (-1)^x % 3
所以只要统计奇数位和偶数位上有多少个1就好了,时间复杂度O(len)
代码:
#include
using namespace std;
int main()
{
string s;
while(cin>>s)
{
int len=s.length();
int ans=0;
for(int i=len-1,j=0;i>=0;i--,j++)
{
if(s[i]=='1')
{
ans+=j&1?2:1;
ans%=3;
}
}
cout<
七、(今日头条2017)栈是先进后出的数据结构,给定一个大小为3的初始状态为空的栈,已知一组数据经过这个栈后,最终的数据顺序依次为:1 3 2 4 问原始进栈的数据不可能是以下的哪组?
A. 2、3、1、4
B. 3、1、2、4
C. 4、2、3、1
D. 1、4、3、2
思想:答案是C A:进进进出出出进出 B:进进出出进出进出 C:进进进进出出出出 D:进出进进出进出出 迷惑点有二,一是D选项乍一看成不了,其实D也可以,第二个迷惑点是栈的大小是3,C选项要成的话空间不够。所以这题很容易选成D