剑指Offer 03-07题解
目前我做过的剑指Offer…
剑指Offer 03. 数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
来源:力扣(LeetCode)
方法一: 哈希表
采用哈希表储存数字出现的的次数,当其大于1时,则表示该数字重复出现了。
代码 : 时间O(n) 空间O(n)
class Solution {
public:
int findRepeatNumber(vector<int>& nums)
{
unordered_map<int, int> nums_map;
for (auto& num : nums) //遍历数组nims
{
if (++nums_map[num] > 1) //出现次数大于1
return num;
}
return -1; //无重复返回-1
}
};
方法二: 原地哈希
由于题目所给数组 nums 中的n个数字的范围是在 0~n-1 之间
所以 nums 数组中的每一个数字都可以有与其对应相等的数组下标。 即: nums[i]=i
移动数字到其对应下标的位置,若该位置已被占用且满足:nums[i]=i ,则表示该数字重复出现
代码 : 时间O(n) 空间O(1)
class Solution {
public:
int findRepeatNumber(vector<int>& nums)
{
for(int i=0;i<nums.size();++i)
{
while(nums[i]!=i) //判断i是否在其对应下标的位置
{
if(nums[i]==nums[nums[i]]) //看i对应下标的位置是否被占用
return nums[i]; //是 则i重复
swap(nums[i],nums[nums[i]]);//将i换到与他对应的下标位置
}
}
return -1;
}
};
方法三: 快排
将数组 nums 进行快速排序,然后对排序好的数组遍历当满足:nums[i]==nums[i+1] 表示 nums[i] 重复
代码: 时间(nlogn) 空间(1)
class Solution {
public:
int findRepeatNumber(vector<int>& nums)
{
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size()-1;++i)
if(nums[i]==nums[i+1]) //有序数组中 前后相等表示重复
return nums[i];
return -1;
}
};
剑指Offer 04. 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
来源:力扣(LeetCode)
方法一: 暴力
❌两重for循环 暴力解决 时间(nm)空间(1)
方法一: 二叉搜索树
因为数组 从左至右递增 从上至下递增 所以将其旋转四十五度就相当于同一个二叉搜索树
从根节点(matrix[0][m-1]) 开始左边更小右边更大
代码:时间(n+m) 空间(1)
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target)
{
int n=matrix.size()-1; // 行数
if(n<0) // 判断行数是否为空 (为空 则:数组为空)
return false;
int j=matrix[0].size()-1; // 列数
if(j<0) // 判断列数是否为空
return false;
int i=0;
while(matrix[i][j]!=target) // 对比
{
matrix[i][j]>target?--j:++i; // 大减(左移) 小加(下移)
if(j<0||i>n) // 判断是否遍历过界
return false;
}
return true;
}
};
暂时没有更优方法…待补…
剑指Offer 05. 替换空格
请实现一个函数,把字符串 s 中的每一个空格替换成 “ %20 ”
来源:力扣(LeetCode)
方法一: 遍历写入新字符串
创建一个一空字符串ss,遍历字符串s,当为字符时写入ss 为 “ ” 时写入 “%20”
时间 (n) 空间(1)
class Solution {
public:
string replaceSpace(string s) {
string ss;
for(auto &c:s)
{
if(c==' ')
ss+="%20";
else
ss+=c;
}
return ss;
}
};
剑指Offer 06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
来源:力扣(LeetCode)
方法一: 数组反转
直接将节点信息push入数组中,再将数组中的数据反转
代码: 时间(n) 空间(1)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
vector<int> nums;
int i=0;
while(head!=nullptr)
{
nums.push_back(head->val);
++i; // 记录数组元素个数
head=head->next;
}
int num; //交换时用到
int j=0;
for( j,--i;i>j;--i,++j) // 头尾元素互换(即 反转数组)
{
num=nums[i];
nums[i]=nums[j];
nums[j]=num;
}
return nums;
}
};
方法二: 递归
通过函数遍历到链表尾部 ,在层层返回函数对数组插入值
(注意栈溢问题)
代码: 时间(n)空间(n)
class Solution {
public:
void digui(vector<int> &nums,ListNode *head)
{
if(head==nullptr) //判断是否到链表尾部
return ;
digui(nums,head->next);
nums.push_back(head->val);
}
vector<int> reversePrint(ListNode* head) {
vector<int> nums;
digui(nums,head);
return nums;
}
};
剑指Offer 07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
来源:力扣(LeetCode)
方法一: 分治递归
前序遍历顺序为 root ->left ->right
中序遍历顺序为 left ->root ->right
前序遍历的每一个结果 对应在中序遍历里 root 的位置将其分为左子树和右子树
在对左右子树[中序遍历的左右子区间]分别进行上述操作即可重建二叉树
定位方式:<注意仅限此题,若有重复元素定位会出错>
利用哈希表定位前序遍历中每个元素在中序遍历中的位置
代码: 时间(n) 空间(n)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
this->preorder=preorder; //递归中要使用preorder ,so 将其内容传到整个类
for(int i=0;i<inorder.size();++i)
map[inorder[i]]=i; //利用哈希表定位perorder每个元素在inorder中的位置
return recur(0,0,inorder.size()-1);
}
TreeNode* recur(int root,int left,int right)
{ //root 根节点在perorder的位置
//left 子区间左边界
//right子区间右边界
if(left>right) return nullptr; //判空(左/右子区间为空时 结束)
TreeNode *node=new TreeNode(preorder[root]);
int i=map[preorder[root]]; //使用哈希定位的位置
node->left=recur(root+1,left,i-1); //左区间
node->right=recur(root+i+1-left,i+1,right); //右区间
return node;
}
unordered_map<int ,int> map; //哈希定位用
vector<int> preorder;
};