本回答持续更新……
通常空间复杂度指的是Auxiliary Space(辅助空间)。
首先,很多数学相关的题目空间都是O(1)的,有些甚至时间也是O(1)的。
打个样:
判断数字是否是2的幂
int power_of_2(int n) {
return !((n-1) & n);
}
不用循环统计自然数中数字个数
int count_digit(long n) {
return floor(log10(n)) + 1;
}
下面是时间不是O(1),空间是O(1)
判断二进制中1的个数
《剑指Offer》有收录。
int hammingWeight(uint32_t n) {
int num = 0;
while (n) {
n &= (n-1);
num++;
}
return num;
}
寻找缺失数字
leetcode: 268
直接搬运:
class Solution {
public:
int missingNumber(vector& nums) {
int x1 = 0;
for (int num: nums) {
x1 = x1 ^ num;
}
int max = nums.size();
int x2 = 0;
for (int i = 0; i <= max; ++i) {
x2 = x2 ^ i;
}
return (x1 ^ x2);
}
};
寻找只出现一次的1个数字
数组中有一个数字只出现一次,其余都出现两次。找出这个数。
不要用hash,不要用map。O(1)空间的话,肯定还是异或啦。全员异或就行。
LeetCode 136:
class Solution {
public:
int singleNumber(vector& nums) {
int res = 0;
for (int n: nums) {
res ^= n;
}
return res;
}
};
寻找只出现一次的2个数字
数组中有两个数字只出现一次,其余都出现两次。找出这两个数。
这题应该是出自《剑指Offer》:
在LeetCode上也有收录。
其实就是分组异或!
class Solution {
public:
vector singleNumbers(vector& nums) {
int res = 0;
for (int n: nums) {
res ^= n;
}
int i = 1;
while ((res & i) != i) {
i <<= 1;
}
int a = 0;
int b = 0;
for (int n: nums) {
if ((n & i) == 0) {
a ^= n;
} else {
b ^= n;
}
}
return {a, b};
}
};
收缩数组
这类题目很多。比如一个整数数组,把数字0提到数组前面,其余数字顺序保持不变。
最简单的想法就是O(n)空间了。但是根本不需要……
void compact(int* num, int n) {
int i = n - 1, j = n - 1;
for (; j >= 0; j--) {
if (num[j] != 0) {
num[i] = num[j];
i--;
}
}
for (; i >= 0 ; i--) {
num[i] = 0;
}
}
int main() {
int num[] = {1, 0, 0, 3, 0, 0, 0, 4, 5, 0, 2};
compact(num, 10);
for (int i = 0; i < 10; ++i) {
printf("%d\n", num[i]);
}
}
另外变种很多。比如:去除一个字符串中的空格。不影响其他字符的顺序。
字符串向右循环移动K位编程之美2.17
将字符串向右循环移动 k 位。比如abcd1234向右移动4位是1234abcd。解法有很多,不暴力的情况下,时间和空间最优的解法是:
将 abcd1234,按k位分隔成两段,得到abcd和1234,这两段单独翻转,得到 dcba4321,然后对整个字符串进行翻转,得到 1234abcd。代码:
void reverse(char* arr, int b, int e) {
for (; b < e; b++, e--) {
char temp = arr[e];
arr[e] = arr[b];
arr[b] = temp;
}
}
void right_shift(char* arr, int N, int k) {
k %= N;
reverse(arr, 0, N-K-1);
reverse(arr, N-k, N-1);
reverse(arr, 0, N-1);
}
深度遍历二叉树
是不是以为二叉树深度遍历(先序、中序、后序)的空间复杂度只能O(n)?其实不是。
有种O(1)空间的二叉树遍历方法:Morris遍历。
可以阅读左神的《程序员代码面试指南》:P107。被称之为“遍历二叉树的神级方法”。
核心要点就是废物利用!利用二叉树的叶子节点指针(原先指向NULL)。
排序的题目
很多排序都是O(1)空间。当然并不是所有排序都是。也可以看出来快排和归并排序都是空间换时间。来源网络