数组
常见题目
把两个排序好的数组合并成一个排序好的数组
解法:双指针,先判断越界,然后比较的时候要注意维持稳定性。把几种情况合并来写。
int Merge(int *a, int na, int *b, int nb, int *c) {
int pa = 0, pb = 0, pc = 0;
while(pa < na || pb < nb) {
if(pa == na || (pb < nb && a[pa] > b[pb])) {
c[pc] = b[pb];
++pc;
++pb;
continue;
} else {
c[pc] = a[pa];
++pc;
++pa;
continue;
}
}
return pc;
}
把数组中的负数都移动到正数的前面,不改变负数之间的顺序和正数之间的顺序
解法:假如可以改变顺序,就像第k大一样去调整0的位置就可以了,但是这里不允许改变顺序,简单的方法有两种,一种是时间O(n^2),空间O(1)的插入排序,另一种是复制一遍的时间O(n),空间O(n)的归并排序。
有一种比较花里胡哨的方法,当值域小于int表示范围的sqrt的时候可以弄。
1.扫描一次数组,数出有多少个正数以及有多少个负数,同时求出最大值和最小值。
2.判断全正数或者全负数的情况。
3.把每个数减去最小值(保证最小值是负数),然后加上值域范围M=max-min+1。使得每个数变成非负数,并且乘以M(使用M进制数的高位记录这个数原本的信息)。
4.分别生成正数指针和负数指针,指向他们应该去的第一个位置。
5.扫描一次数组,把每个数原本的信息还原出来,记录在该去的指针指向的位置的低位。
6.扫描一次数组,把高位丢掉(模M),把低位加上最小值(保证最小值是负数)。
启示:可以利用数组中元素的值域,强行生成出空间,方法是分成高位和低位记录,本质上和用两个short进行归并差不多,不过非常巧妙。
void Solve(int *a, int n) {
int cntn = 0, mina = 0, maxa = 0;
for(int i = 0; i < n; ++i) {
if(a[i] < 0) {
++cntn;
if(a[i] < mina)
mina = a[i];
} else {
if(a[i] > maxa)
maxa = a[i];
}
}
int M = maxa - mina + 1;
for(int i = 0; i < n; ++i) {
a[i] -= mina;
a[i] *= M;
}
int pn = 0, pp = cntn;
for(int i = 0; i < n; ++i) {
if(a[i] < (0 - mina)*M) {
a[pn] += a[i] / M;
++pn;
} else {
a[pp] += a[i] / M;
++pp;
}
}
for(int i = 0; i < n; ++i) {
a[i] %= M;
a[i] += mina;
}
return;
}
链表
翻转链表
https://leetcode-cn.com/problems/reverse-linked-list/submissions/
非常简单,保存一下cur_next=cur->next,然后把cur->next=revHead,再revHead=cur,最后cur=cur_next。其实发现这四个构成一个循环。
栈
简单介绍一下栈
栈是一种先进后出的数据结构,必须要实现的接口为:Push,Pop,Top。
面向对象的栈
class Stack {
private:
int *data;
int maxSize;
int top;
public:
Stack(int maxSize): maxSize(maxSize) {
data = new int [maxSize + 1];
top = 0;
return;
}
void Clear() {
top = 0;
return;
}
int Size() {
return top;
}
int Top() {
if(top == 0)
exit(-1);
return data[top];
}
void Push(int value) {
if(top == maxSize)
exit(-1);
++top;
data[top] = value;
return;
}
void Pop() {
if(top == 0)
exit(-1);
--top;
return;
}
};
参考资料
代码面试需要知道的8种数据结构(附面试题及答案链接) - Fundebug - 博客园
面试必刷-《剑指offer》刷题小结 - 简书