时间复杂度为O(n),空间复杂度为O(1)的典型问题搜集:
对换思想;
一次遍历求得统计信息,二次遍历算法求解;
利用固定大小的空间存放统计信息;
利用已知子问题的解...
1.字符串左移,void*pszStringRotate(char *pszString, intnCharsRotate),比如 ABCDEFG,移3 位变 DEFGABC,要求空间复杂度 O(1),时间复杂度 O(n)
(分析:分析与解法
假设原数组序列为abcd1234,要求变换成的数组序列为1234abcd,即循环右移了4位,比较之后,不难看出,其中有两段的顺序是不变的:1234和abcd,可把两段看成两个整体。右移K位的过程就是把数组的两部分交换一下。变换过程通过以下步骤完成:
1.逆序排列 abcd: abcd1234-> dcba1234; //前n-k位逆序(对换)
2.逆序排列 1234:dcba1234-> dcba4321;//后k为逆序
3.全部逆序dcba4321->1234abcd。//全体逆序
)
2. 对n个数排序,要求时间复杂度为O(n),空间复杂度为O(1)
假定你的数字范围在0到65535范围之内,定义一个数组count[65536](这个空间是常量,和n无关,所以是O(1) ),初值全部为0。
那么假设有下面这些数字:
100 200 300 119 0 6
...
那么对于每个这个数字,都做在count中记录一下:
100 => count[100]++
200 => count[200]++
300 => count[300]++
119 => count[119]++
0 => count[0]++
6 => count[6]++
...
最后,遍历一边所有这些数字就可得到0~65535每个数字的个数(在count数组中),然后再顺序遍历count数组,count[n] = m,则输出m个n,(比如说有count[3] = 2, 那么说明有2个数字3),依次输出,最后可得结果。第一次遍历是O(n),第二次遍历是O(1),为常量,所以最后的时间复杂度为O(n),而空间复杂度为O(1)
3.1删除字符串中的连续空格时间复杂度为O(n),而空间复杂度为O(1)
(分析:设置两个指针,一个用于遍历,一个用于结果的拷贝。后面的元素写入前面对应的位置
Eg:
)
char* trim(char* a)
{//i指针拷贝后面或者当前元素到当前位置,j遍历数组元素结点
int i=-1,j=0;
for (;a[j]!='\0';j++)
{
if (a[j]==a[j+1] && a[j+1]==' ')
{
//skip more than one blank
while (a[j]==' ')
{
++j;
}
--j;// go back to the last blank
}
a[++i]=a[j];
}
a[++i]='\0';
return a;
}
3.2 替换空格
问题:请实现一个函数,把字符串中的每个空格替换成“%20”。例如输入“We are happy.",则输出”We%20are%20happy."
分析:在空间复杂度尽可能低的情况下,不允许开辟一个新的数组来存放替换空格后的字符串。如果从前往后替换字符串,那么保存在空格后面的字符串肯定会被覆盖。假设字符串的长度为n。对每个空格字符,需要移动后面O(n)个字符,因此对含有O(n)个空格字符的字符串而言总的时间复杂度是O(n^2),明显不可取。
从后往前进行替换,时间复杂度降为O(n)。
(1)首先遍历一遍字符串,找出字符串的长度以及其中的空格数
(2)根据原字符串的长度和空格数求出最后新的字符串的长度
(3)设置两个指针分别指向原字符串和新字符串的末尾位置
(4)如果原字符串的指针指向的内容不空,则将内容赋值给新指针指向的位置;否则从新指针开始向前赋值“02%”
(5)直到两个指针相等时表明字符串中的所有空格已经替换完毕
4.判断一个数组中是否有重复元素 要求时间复杂度O(n),空间复杂度O(1)
数组map的思想
要求空间复杂度为O(1),那么可以申请常数大小的空间,由于int最大表示范围为65536,我们可以直接申请65536大小的数组b。
将原数组中的a[i],通过b[a[i]]++,来进行计数,如果值超过1,则表明有重复。
优点:
申请空间比较大
5.(联系4)统计数组中不同元素出现的次数(时间复杂度O(n),空间复杂度o(1))
6.数对之差的最小值
题描述:在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。
思路:这又是一道动态规划的题目,这是我能想到的最好方法,时间复杂度为O(n)。假设f[i]表示数组中前i+1个数的解,前i+1个数的最大值为m[i]。则有下列式子。
f[i] = max(f[i-1], m[i-1]- a[i]), m[i] = max(m[i-1],a[i])。
7.寻找超过一半的元素
1. /*n个字符的数组,只有一个元素出现的次数最多,找出该元素*/
2. char FindIt(char a[],int n)
3. {
4. char ch;
5. int times=0;
6. int i;
7. for(i=0;i 8. { 9. if(times==0)/*计数清零,从本次开始选取新的字符*/ 10. { 11. ch=a[i]; 12. times=1; 13. } 14. else if(ch==a[i])/*找到相同的计数加1*/ 15. times++; 16. else/*与备选的字符ch不同,计数-1.做一次抵消。只有次数最多的才会保留到最后*/ 17. times--; 18. } 19. return ch; 20. } 21.