剑指offer
作者:互联网
目录
数据结构-数组
数组中重复的数字
这个绝对不是简单题,是与面试官交流的问题
- 时间优先:字典,哈希表
- 空间优先:利用题中性质:
范围在\(0...n-1\)所以如果没出现重复的数,重排之后是按照0~n-1这样排序的。
这题简单的方法是直接排序,这样时间复杂度\(O(nlogn)\)
但是可以更优化一下,如果当前位置\(i\)不等于\(a[i]\),就让位置\(i\)与位置\(a[i]\)的值交换
这样每个数最多交换两次,第一次交换到\(i\)位置,第二次交换回到正确位置
如果\(a[i]==a[a[i]]\),那么说明找到重复的了
时间复杂度 \(O(n)\) 空间复杂度\(O(n)\)
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
int ans = -1;
for(int i = 0;i < nums.size();++i){
while(i!=nums[i]){
if(nums[nums[i]] == nums[i]) {
ans = nums[i];
break;
}
else swap(nums[i],nums[nums[i]]);
}
if(ans != -1) break;
}
return ans;
}
};
二维数组中的查找
第一次我直接用二分
但是有更简单的做法,如果站在右上角看的话就是一个查找二叉树
时间复杂度\(O(logn)\)
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
bool isFound = 0;
if(matrix.empty()) return 0;
int m = matrix[0].size(),n = matrix.size();
int i = 0,j = m - 1;
while(i < n && j != -1){
if(matrix[i][j] == target){
isFound = 1;
break;
}
if(matrix[i][j] > target){
--j;
}
else if(matrix[i][j] < target){
++i;
}
}
return isFound;
}
};
这题更重要的是测试样例
- 二维数组里存在的数
- 不存在的数
- 空指针
替换空格
如果是要求时间最快写得最简单,完全可以新建字符串
时间复杂度\(O(n)\),空间复杂度$O(n) $
class Solution {
public:
string replaceSpace(string s) {
int len = s.length();
if(len == 0) return s;
string ans;
for(int i = 0;i < len;++i){
if(s[i]==' '){
ans += "%20";
}
else ans += s[i];
}
return ans;
}
};
如果要求空间最小,那么需要在原字符串上进行替换操作。
- \(O(n^2)\):这个很容易想到,每出现一个空格,后面就移位
- \(O(n)\):采用从后往前的做法,这样每个字符只用移动一次
先求出空格个数,设定两个指针,一个指向要移动到的位置,一个指向原来的位置
ps:这题leetcode上差点意思,我就在牛客上提交的
时间复杂度\(O(n)\),没有新开空间
class Solution {
public:
void replaceSpace(char *str,int length) {
if(length == 0) return;
int numberOfBlank = 0;
for(int i = 0;i < length;++i){
if(str[i] == ' ') numberOfBlank++;
}
int newStingLength = length + (numberOfBlank << 1);
int p1 = newStingLength - 1,p2 = length - 1;
while(p2 >= 0){
if(str[p2] == ' '){
str[p1--] = '0';
str[p1--] = '2';
str[p1--] = '%';
}else{
str[p1--] = str[p2];
}
p2--;
}
}
};
数据结构-链表
从头到尾打印链表
一开始我写成了不能开辟额外空间的链表反转
这种情况一定要问清楚,可不可以改变原链表的形状
时间复杂度\(O(n)\)
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
vector<int> ans;
if(head == NULL) return ans;
ListNode *preNode = NULL,*nowNode = head,*tmpNode = NULL;
while(nowNode->next){
tmpNode = nowNode->next;
nowNode -> next = preNode;
preNode = nowNode;
nowNode = tmpNode;
}
nowNode -> next = preNode;
while(nowNode){
ans.push_back(nowNode->val);
nowNode = nowNode -> next;
}
return ans;
}
};
但是这种题已经要求了用数组存,那就可以用更简单更快的方法
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
vector<int> ans;
if(head == NULL) return ans;
ListNode *nowNode = head;
int listLength = 0;
while(nowNode){
ans.push_back(nowNode->val);
nowNode = nowNode ->next;
listLength++;
}
for(int i = 0;i < listLength/2;++i){
swap(ans[i],ans[listLength-i-1]);
}
return ans;
}
};
翻转可以当作以中间的数作为根节点,然后左右子树交换。
除此之外还可采用栈的方法。
数据结构-树
标签:return,nums,int,复杂度,offer,ans,nowNode 来源: https://www.cnblogs.com/smallocean/p/12487468.html