剑指offer题集(上:简单题)
(题目来自于leetcode)
代码为2个版本c++
python
简单题
文章目录
- 剑指offer题集(上:简单题)
- 简单题
- [剑指 Offer 03. 数组中重复的数字](https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/)
- [剑指 Offer 05. 替换空格](https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/)
- [剑指 Offer 06. 从尾到头打印链表](https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/)
- [剑指 Offer 09. 用两个栈实现队列](https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/)
- [剑指 Offer 10- I. 斐波那契数列](https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/)
- [剑指 Offer 10- II. 青蛙跳台阶问题](https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/)
- [剑指 Offer 11. 旋转数组的最小数字](https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/)
- [剑指 Offer 15. 二进制中1的个数](https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/)
- [剑指 Offer 17. 打印从1到最大的n位数](https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/)
- [剑指 Offer 18. 删除链表的节点](https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/)
- [剑指 Offer 21. 调整数组顺序使奇数位于偶数前面](https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/)
- [剑指 Offer 22. 链表中倒数第k个节点](https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
- [剑指 Offer 24. 反转链表](https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/)
- [剑指 Offer 25. 合并两个排序的链表](https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof/)
- [剑指 Offer 27. 二叉树的镜像](https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/)
- [剑指 Offer 28. 对称的二叉树](https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof/)
- [剑指 Offer 29. 顺时针打印矩阵](https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/)
- [剑指 Offer 30. 包含min函数的栈](https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/)
- [剑指 Offer 39. 数组中出现次数超过一半的数字](https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/)
- [剑指 Offer 40. 最小的k个数](https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/)
- [剑指 Offer 42. 连续子数组的最大和](https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/)
- [剑指 Offer 50. 第一个只出现一次的字符](https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/)
- [剑指 Offer 52. 两个链表的第一个公共节点](https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/)
- [剑指 Offer 53 - I. 在排序数组中查找数字 I](https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/)
- [剑指 Offer 53 - II. 0~n-1中缺失的数字](https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/)
- [剑指 Offer 54. 二叉搜索树的第k大节点](https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/)
- [剑指 Offer 55 - I. 二叉树的深度](https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/)
- [剑指 Offer 55 - II. 平衡二叉树](https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/)
- [剑指 Offer 57. 和为s的两个数字](https://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof/)
- [剑指 Offer 57 - II. 和为s的连续正数序列](https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/)
- [剑指 Offer 58 - I. 翻转单词顺序](https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/)
- [剑指 Offer 58 - II. 左旋转字符串](https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/)
- [剑指 Offer 59 - I. 滑动窗口的最大值](https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/)
- [剑指 Offer 61. 扑克牌中的顺子](https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/)
- [剑指 Offer 62. 圆圈中最后剩下的数字](https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/)
- [剑指 Offer 65. 不用加减乘除做加法](https://leetcode-cn.com/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/)
- [剑指 Offer 68 - I. 二叉搜索树的最近公共祖先](https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-zui-jin-gong-gong-zu-xian-lcof/)
- [剑指 Offer 68 - II. 二叉树的最近公共祖先](https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/)
剑指 Offer 03. 数组中重复的数字
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
题解
遍历数组
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
vector<int> d(nums.size()+1);
for(int i=0;i<nums.size();i++){
if(d[nums[i]]!=0)
return nums[i];
else
d[nums[i]]=1;
}
return 0;
}
};
// 或者
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
map<int,int> m;
for(int i=0;i<nums.size();i++){
if(m.find(nums[i])!=m.end())
return nums[i];
else
m[nums[i]]=1;
}
return 0;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( n ) O(n) O(n)
剑指 Offer 05. 替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”
限制:
0 <= s 的长度 <= 10000
题解
class Solution {
public:
string replaceSpace(string s) {
string answer;
for(char c:s){
if(c==' '){
answer.push_back('%');
answer.push_back('2');
answer.push_back('0');
}
else
answer.push_back(c);
}
return answer;
}
};
//or
class Solution {
public:
string replaceSpace(string s) {
string answer;
for(char c:s){
if(c==' '){
answer+="%20";
}
else
answer+=c;
}
return answer;
}
};
-
时间复杂度 O ( n ) O(n) O(n)
-
空间复杂度 O ( n ) O(n) O(n)
剑指 Offer 06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
题解
insert
函数
/**
* 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> answer;
while(head!=NULL){
answer.insert(answer.begin(),head->val);
head=head->next;
}
return answer;
}
};
栈
/**
* 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> answer;
stack<int> s;
while(head!=NULL){
s.push(head->val);
head=head->next;
}
while(!s.empty()){
answer.push_back(s.top());
s.pop();
}
return answer;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( n ) O(n) O(n)
剑指 Offer 09. 用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
示例 1:
输入:
[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:
输入:
[“CQueue”,“deleteHead”,“appendTail”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
提示:
1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用
题解
插入操作中,无须把所有元素全都放在一个栈中,看看代码就懂了
插入元素
插入元素对应方法 appendTail
stack1
直接插入元素
删除元素对应方法 deleteHead
- 如果
stack2
为空,则将stack1
里的所有元素弹出插入到stack2
里 - 如果
stack2
仍为空,则返回 -1,否则从stack2
弹出一个元素并返回
class CQueue {
stack<int> stack1,stack2;
public:
CQueue() {
while (!stack1.empty()) {
stack1.pop();
}
while (!stack2.empty()) {
stack2.pop();
}
}
void appendTail(int value) {
stack1.push(value);
}
int deleteHead() {
// 如果第二个栈为空
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
if (stack2.empty()) {
return -1;
} else {
int deleteItem = stack2.top();
stack2.pop();
return deleteItem;
}
}
};
- 时间复杂度 O ( 1 ) O(1) O(1) 官方说法是删除插入都是1,插入为什么是1,不太懂。。。。
- 空间复杂度 O ( n ) O(n) O(n)
剑指 Offer 10- I. 斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
提示:
0 <= n <= 100
题解
C++版
class Solution {
public:
int fib(int n) {
if(n==0)
return 0;
else if(n==1)
return 1;
int answer=0,cur=1,last=0;
for(int i=2;i<=n;i++){
int tmp=cur;
cur=(cur+last)%1000000007;
last=tmp;
}
return cur;
}
};
//别人的优秀代码 作者:zhu-zhou-t
class Solution {
public:
int fib(int n) {
int arr[2] = {0, 1};
for(int i = 2; i <= n; ++i) {
arr[i & 1] = (arr[0] + arr[1]) % (int)(1e9 + 7);
}
return arr[n & 1];
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def fib(self, n: int) -> int:
a=0
if n==0:
return 0
b=1
for i in range(n-1):
a,b=b,(a+b)%1000000007
return b
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 10- II. 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
示例 3:
输入:n = 0
输出:1
提示:
0 <= n <= 100
题解
其实和上一题一样
C++
class Solution {
public:
int numWays(int n) {
int cur=1,last=0;
for(int i=1;i<=n;i++){
int tmp=cur;
cur=(cur+last)%1000000007;
last=tmp;
}
return cur;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def numWays(self, n: int) -> int:
a=0
b=1
for _ in range(n):
a,b=b,(a+b)%1000000007
return b;
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
题解
C++
class Solution {
public:
int minArray(vector<int>& numbers) {
int last=numbers[0];
for(int i:numbers){
if(i<last)
return i;
}
return numbers[0];
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
二分法
class Solution {
public:
int minArray(vector<int>& numbers) {
int low=0;
int high=numbers.size()-1;
while(low<high){
int pivot=low+(high-low)/2;
if(numbers[pivot]<numsbers[high])
high=pivot;
else if(numbers[pivot]>numbers[high])
low=pivot+1;
else
high-=1;
}
return numbers[low];
}
};
- 平均时间复杂度 O ( l o g ( n ) ) O(log(n)) O(log(n))
- 空间复杂度 O ( 1 ) O(1) O(1)
python
#投机取巧版
class Solution:
def minArray(self, numbers: List[int]) -> int:
return min(numbers);
#一般版
class Solution:
def minArray(self, numbers: List[int]) -> int:
last=numbers[0]
for i in numbers:
if i<last:
return i
return numbers[0]
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 15. 二进制中1的个数
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。
提示:
输入必须是长度为 32 的 二进制串
题解
c++
class Solution {
public:
int hammingWeight(uint32_t n) {
int answer=0;
while(n>0){
answer+=n&1;
n=n>>1;
}
return answer;
}
};
- 时间复杂度 O ( l o g 2 n ) O(log_2n) O(log2n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def hammingWeight(self, n: int) -> int:
answer=0
while n:
answer+=n&1
n>>=1
return answer
- 时间复杂度 O ( l o g 2 n ) O(log_2n) O(log2n)
- 空间复杂度 O ( 1 ) O(1) O(1)
n&(n-1)法
(n−1) 解析: 二进制数字 nn 最右边的 1 变成 0 ,此 1 右边的 0 都变成 1。
n & (n - 1) 解析: 二进制数字 n 最右边的 1 变成 0 ,其余不变。
class Solution:
def hammingWeight(self, n: int) -> int:
res = 0
while n:
res += 1
n &= n - 1
return res
- 时间复杂度 O ( M ) O(M) O(M) M为n中1的个数
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 17. 打印从1到最大的n位数
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
说明:
用返回一个整数列表来代替打印
n 为正整数
题解
C++
class Solution {
public:
vector<int> printNumbers(int n) {
int end=pow(10,n);
vector<int> ans;
for(int i=1;i<end;i++)
ans.push_back(i);
return ans;
}
};
- 时间复杂度 O ( 1 0 n ) O(10^n) O(10n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def printNumbers(self, n: int) -> List[int]:
return list(range(1,10**n))
- 时间复杂度 O ( 1 0 n ) O(10^n) O(10n)
- 空间复杂度 O ( 1 ) O(1) O(1)
大数
。。。不会
剑指 Offer 18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
题目保证链表中节点的值互不相同
若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
题解
C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
if(head->val==val)
return head->next;
ListNode* cur=head->next,*last=head;
while(cur!=NULL){
if(cur->val==val){
last->next=cur->next;
break;
}
cur=cur->next;
last=last->next;
}
return head;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
vhead=ListNode()
vhead.next=head
cur=head
last=vhead
while cur!=None:
if cur.val==val:
last.next=cur.next
break
cur=cur.next
last=last.next
return vhead.next
##看来我还没有得到python的真谛 作者:jyd
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
if head.val == val: return head.next
pre, cur = head, head.next
while cur and cur.val != val:
pre, cur = cur, cur.next
if cur: pre.next = cur.next
return head
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例:
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
提示:
0 <= nums.length <= 50000
1 <= nums[i] <= 10000
题解
我用的首尾指针,还可以用快慢指针
class Solution {
public:
vector<int> exchange(vector<int>& nums) {
int begin=0,end=nums.size()-1;
while(begin<end){
if(nums[begin]%2==1)
begin++;
else if(nums[end]%2==0)
end--;
else if(nums[begin]%2!=1){
int tmp=nums[begin];
nums[begin]=nums[end];
nums[end]=tmp;
}
}
return nums;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
f=0
s=0
while f<len(nums):
if nums[f]&1 :
nums[s],nums[f]=nums[f],nums[s]
s+=1
f+=1
return nums
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
题解
C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
ListNode* fast=head,*slow=head;
for(int i=0;i<k-1;i++)
fast=fast->next;
while(fast->next!=NULL){
fast=fast->next;
slow=slow->next;
}
return slow;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
fast=head;slow=head
for _ in range(k-1):
fast=fast.next
while fast.next!=None:
fast,slow=fast.next,slow.next
return slow;
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
限制:
0 <= 节点个数 <= 5000
题解
C++
C++用递归做的
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL or head->next==NULL)
return head;
ListNode* rhead=reverseList(head->next),*cur=rhead;
while(cur->next!=NULL)
cur=cur->next;
cur->next=head;
head->next=NULL;
return rhead;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( n ) O(n) O(n)
python
普通迭代
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
cur=head
pre=None
while cur!=None:
tmp=cur.next
cur.next=pre
pre,cur=cur,tmp
return pre
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 25. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
限制:
0 <= 链表长度 <= 1000
题解
c++
感觉自己写的代码就是一坨。。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* head=new ListNode(),*cur=head;
while(l1!=NULL and l2 !=NULL){
if(l1->val>=l2->val){
cur->next=l2;
l2=l2->next;
}
else{
cur->next=l1;
l1=l1->next;
}
cur=cur->next;
}
if(l1!=NULL)
cur->next=l1;
else
cur->next=l2;
return head->next;
}
};
- 时间复杂度 O ( n + m ) O(n+m) O(n+m) l1和l2的长度和
- 空间复杂度 O ( 1 ) O(1) O(1)
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if l1==None:
return l2;
if l2==None:
return l1;
if l1.val<=l2.val:
l1.next=self.mergeTwoLists(l1.next,l2)
return l1
if l2.val<l1.val:
l2.next=self.mergeTwoLists(l1,l2.next)
return l2;
- 时间复杂度 O ( n + m ) O(n+m) O(n+m) l1和l2的长度和
- 空间复杂度 O ( n + m ) O(n+m) O(n+m)
剑指 Offer 27. 二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/
2 7
/ \ /
1 3 6 9
镜像输出:
4
/
7 2
/ \ /
9 6 3 1
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
题解
C++
递归 DFS
/**
* 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* mirrorTree(TreeNode* root) {
if(root==NULL)
return NULL;
TreeNode* tmp=root->left;
root->left=mirrorTree(root->right);
root->right=mirrorTree(tmp);
return root;
}
};
- 时间复杂度 O ( n ) O(n) O(n) 节点个数
- 空间复杂度 O ( n ) O(n) O(n)
python
辅助栈法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
if not root: return root;
s=[root]
while s:
cur=s.pop()
if cur.right: s.append(cur.right)
if cur.left: s.append(cur.left)
cur.left,cur.right=cur.right,cur.left
return root;
- 时间复杂度 O ( n ) O(n) O(n) 节点个数
- 空间复杂度 O ( n ) O(n) O(n)
剑指 Offer 28. 对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/
2 2
/ \ /
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/
2 2
\
3 3
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
限制:
0 <= 节点个数 <= 1000
题解
C++
双栈法,对左右子树同时遍历,只不过方向相反。
/**
* 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:
bool isSymmetric(TreeNode* root) {
if(root==NULL)
return true;
TreeNode* lcur=root->left,*rcur=root->right;
stack<TreeNode*> sl,sr;
sl.push(lcur);
sr.push(rcur);
while(!sl.empty() && !sr.empty()){
lcur=sl.top();
rcur=sr.top();
sl.pop(),sr.pop();
if(lcur!=NULL && rcur !=NULL)
if(lcur->val!=rcur->val)
return false;
else{
sl.push(lcur->left);
sl.push(lcur->right);
sr.push(rcur->right);
sr.push(rcur->left);
}
else if(lcur==NULL && rcur ==NULL)
continue;
else
return false;
}
if(lcur==NULL && rcur==NULL)
return true;
return false;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( n ) O(n) O(n)
python
递归法,新建一个比较函数
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def cur(L,R) :
if not L and not R: return True
if not L or not R or L.val != R.val: return False
return recur(L.left, R.right) and recur(L.right, R.left)
return root==None or cur(root.left,root.right)
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( n ) O(n) O(n)
剑指 Offer 29. 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
限制:
0 <= matrix.length <= 100
0 <= matrix[i].length <= 100
题解
c++
定位四个顶点坐标,每走一圈就是一个循环
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> ans;
if(matrix.size()==0)
return ans;
int htop=0,wtop=0,h=matrix.size(),w=matrix[0].size();
int i=htop,j=wtop;
cout<<i<<";"<<j<<endl;
while(true){
cout<<i<<";fir;"<<j<<endl;
for(i=htop,j=wtop;j<w;j++){
cout<<i<<";"<<j<<endl;
ans.push_back(matrix[i][j]);
}
htop++;
if(htop>=h)
break;
for(i+=1,j=w-1;i<h;i++){
cout<<i<<";"<<j<<endl;
ans.push_back(matrix[i][j]);
}
w--;
if(wtop>=w)
break;
for(i=h-1,j=w-1;j>=wtop;j-- ){
cout<<i<<";"<<j<<endl;
ans.push_back(matrix[i][j]);
}
h--;
if(htop>=h)
break;
for(i=h-1,j=wtop;i>=htop;i--){
cout<<i<<";"<<j<<endl;
ans.push_back(matrix[i][j]);
}
wtop++;
if(wtop>=w)
break;
}
return ans;
}
};
- 时间复杂度 O ( m ∗ n ) O(m*n) O(m∗n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if len(matrix)==0:return [];
top=0
bottom=len(matrix)
left=0
right=len(matrix[0])
ans=[]
while True:
for j in range(left,right):
ans.append(matrix[top][j])
top+=1
if top>=bottom:break
for i in range(top,bottom):
ans.append(matrix[i][right-1])
right-=1
if left>=right:break;
for j in range(right-1,left-1,-1):
ans.append(matrix[bottom-1][j])
bottom-=1
if top>=bottom:break
for i in range(bottom-1,top-1,-1):
ans.append(matrix[i][left])
left+=1
if left>=right:break
return ans
- 时间复杂度 O ( m ∗ n ) O(m*n) O(m∗n)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 30. 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.
提示:
各函数的调用总次数不超过 20000 次
题解
C++
辅助栈
class MinStack {
stack<int> s,s_min;
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
s.push(x);
if(!s_min.empty() && x>=s_min.top())
s_min.push(s_min.top());
else
s_min.push(x);
}
void pop() {
if(!s.empty()){
s.pop();
s_min.pop();
}
}
int top() {
return s.top();
}
int min() {
return s_min.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(x);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->min();
*/
python
相比于C++版,同样是辅助栈,但辅助栈中只存放必要的最小值
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.L=[]
self.L_min=[]
def push(self, x: int) -> None:
self.L.append(x)
if not self.L_min or self.L_min[-1]>=x : self.L_min.append(x)
def pop(self) -> None:
if self.L[-1]==self.L_min[-1]:self.L_min.pop()
self.L.pop()
def top(self) -> int:
return self.L[-1]
def min(self) -> int:
return self.L_min[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()
剑指 Offer 39. 数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
限制:
1 <= 数组长度 <= 50000
题解
C++
//排序,中值
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(),nums.end());
return nums[int(nums.size()/2)];
}
};
//摩尔投票法 时间复杂度O(n),空间复杂度O(1)
class Solution {
public:
int majorityElement(vector<int>& nums) {
int votes=0,x=0;
for(auto i : nums){
if(!votes) x=i;
votes+= i==x?1:-1;
}
return x;
}
};
//哈希表法 时间复杂度O(n),空间复杂度O(n)
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int,int> m;
for(auto i :nums){
if(++m[i] > nums.size()/2) return i;
}
return -1;
}
python
#排序
class Solution:
def majorityElement(self, nums: List[int]) -> int:
nums.sort()
return nums[len(nums)//2]
剑指 Offer 40. 最小的k个数
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
题解
C++
排序法就不写了,低端!!!!!!!
堆法:
构建一个小根堆,C++默认优先队列是大根堆,因此使用函数greater
修改成小根堆
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
priority_queue<int,vector<int>,greater<int> > a(arr.begin(),arr.end());
vector<int> ans;
while(k){
ans.push_back(a.top());
a.pop();
k--;
}
return ans;
}
};
- 时间复杂度 O ( n ∗ l o g ( n ) ) O(n*log(n)) O(n∗log(n)) 大根堆 插入删除都是 O(logn) 的时间复杂度
- 空间复杂度 O ( n ) O(n) O(n)
好吧,写简单了,应该维护一个小的只有k个数的大根堆
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
if(k==0)
return {};
priority_queue<int> a;
vector<int> ans;
for(int i=0;i<k;i++)
a.push(arr[i]);
for(int i=k;i<arr.size();i++){
if(a.top()>arr[i]){
a.pop();
a.push(arr[i]);
}
}
for(int i=0;i<k;i++){
ans.push_back(a.top());
a.pop();
}
return ans;
}
};
- 时间复杂度 O ( n ∗ l o g ( k ) ) O(n*log(k)) O(n∗log(k)) 大根堆 插入删除都是 O(logk) 的时间复杂度
- 空间复杂度 O ( k ) O(k) O(k)
快排法
之后补上。。。!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!???!!!!!???!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!???!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
python
函数法
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
return heapq.nsmallest(k, arr)
堆
python是最小堆,要取反才能维护前k个小值
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
if k==0:return list()
hp = [-x for x in arr[:k]]
heapq.heapify(hp)
for i in arr[k:]:
if -hp[0] > i:
heapq.heappop(hp)
heapq.heappush(hp,-i)
return [-x for x in hp]
剑指 Offer 42. 连续子数组的最大和
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示:
1 <= arr.length <= 10^5
-100 <= arr[i] <= 100
题解
动态规划
c++
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int m=nums[0],ans=nums[0];
for(int i=1;i<nums.size();i++){
if(m>=0)
m+=nums[i];
else{
m=nums[i];
}
if(ans<m)
ans=m;
}
return ans;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
for i in range(1,len(nums)):
nums[i]+=nums[i-1] if nums[i-1]>0 else 0
return max(nums)
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( 1 ) O(1) O(1) 修改了nums
剑指 Offer 50. 第一个只出现一次的字符
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例:
s = “abaccdeff”
返回 “b”
s = “”
返回 " "
限制:
0 <= s 的长度 <= 50000
题解
c++
先计数,再查找第一个计数为1的字母
class Solution {
public:
char firstUniqChar(string s) {
vector<int> v(26,0);
for(char i : s){
v[i-'a']++;
}
for(char i:s){
if(v[i-'a']==1)
return i;
}
return ' ';
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( k ) O(k) O(k) k为字母的个数 26
python
无序哈希表
class Solution:
def firstUniqChar(self, s: str) -> str:
dic={}
for c in s:
dic[c]= not c in dic
for c in s:
if dic[c] : return c
return ' '
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( k ) O(k) O(k) k为字母的个数 26
剑指 Offer 52. 两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
题解
C++
好吧,是我不浪漫了
走对方的路,寻找她 不同的轨迹终相遇
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA=headA,*curB=headB;
while(curA!=curB){
curA=curA==NULL?headB:curA->next;
curB=curB==NULL?headA:curB->next;
}
return curA;
}
};
- 时间复杂度 O ( N + M ) O(N+M) O(N+M)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 53 - I. 在排序数组中查找数字 I
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
0 <= 数组长度 <= 50000
题解
c++
class Solution {
public:
int search(vector<int>& nums, int target) {
int ans=0;
for(int i=0;i<nums.size();i++){
if(nums[i]>target)
break;
if(nums[i]==target){
while(i<nums.size() && nums[i]==target){
ans++;
i++;
}
break;
}
}
return ans;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
二分法
class Solution:
def search(self, nums: List[int], target: int) -> int:
if len(nums)==0 or nums[len(nums)-1]<target or nums[0]>target :return 0
def recur(left,right):
print(left,right)
if left>right:return 0;
if left==right:
return 1 if nums[left]==target else 0
if nums[(left+right)//2]>target:
return recur(left,(left+right)//2-1)
elif nums[(left+right)//2]<target:
return recur((left+right)//2+1,right)
else:
return 1+recur((left+right)//2+1,right) + recur(left,(left+right)//2-1)
return recur(0,len(nums)-1)
- 时间复杂度 O ( l o g N ) O(logN) O(logN)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 53 - II. 0~n-1中缺失的数字
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例 1:
输入: [0,1,3]
输出: 2
示例 2:
输入: [0,1,2,3,4,5,6,7,9]
输出: 8
限制:
1 <= 数组长度 <= 10000
题解
c++
二分法
class Solution {
public:
int missingNumber(vector<int>& nums) {
int left=0,right=nums.size()-1;
while(left<=right){
int middle=(left+right)/2;
if(middle!=nums[middle])
right=middle-1;
else
left=middle+1;
}
return left;
}
};
- 时间复杂度 O ( l o g N ) O(logN) O(logN)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def missingNumber(self, nums: List[int]) -> int:
l,r=0,len(nums)-1
while l<=r:
m=(l+r)//2
if nums[m] != m : r=m-1
else : l=m+1
return l
- 时间复杂度 O ( l o g N ) O(logN) O(logN)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 54. 二叉搜索树的第k大节点
给定一棵二叉搜索树,请找出其中第k大的节点。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/
1 4
2
输出: 4
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/
3 6
/
2 4
/
1
输出: 4
限制:
1 ≤ k ≤ 二叉搜索树元素个数
题解
c++
中序 倒序遍历,提前终止
/**
* 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:
void dfs(TreeNode *root, TreeNode* & ans,int &k){
if(root==NULL)
return;
dfs(root->right,ans,k);
if(ans==NULL){
k--;
if(k==0)
ans=root;
else
dfs(root->left,ans,k);
}
}
int kthLargest(TreeNode* root, int k) {
TreeNode* ans=NULL;
dfs(root,ans,k);
return ans->val;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
def dfs(root):
if not root:return
dfs(root.right)
if self.k!=0:
self.k-=1;
if self.k==0:self.ans=root.val;
else:dfs(root.left)
self.k=k
dfs(root)
return self.ans
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
剑指 Offer 55 - I. 二叉树的深度
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
提示:
节点总数 <= 10000
题解
c++
计算高度:当前节点的高度等于 1+左右子树最大的高度
由底向上法 dfs
/**
* 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:
int maxDepth(TreeNode* root) {
if(root==NULL)
return 0;
int ld=maxDepth(root->left);
int rd=maxDepth(root->right);
return 1+(ld>rd?ld:rd);
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
BFS
/**
* 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:
int maxDepth(TreeNode* root) {
if(root==NULL)
return 0;
queue<TreeNode*> q;
q.push(root);
int ans=0;
while(!q.empty()){
int n=q.size();
while(n){
TreeNode* cur=q.front();
q.pop();
n--;
if(cur->left!=NULL)
q.push(cur->left);
if(cur->right!=NULL)
q.push(cur->right);
}
ans++;
}
return ans;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
python
dfs
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
剑指 Offer 55 - II. 平衡二叉树
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/
9 20
/
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/
4 4
返回 false 。
限制:
0 <= 树的结点个数 <= 10000
题解
C++
做错了无数遍,终于对了
不用计算不需要的二叉树深度,而且还可以再优化,就是只保存当前节点的左右子树深度就可以,我全保存了。
/**
* 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:
map<TreeNode*,int> m;
int maxdeep(TreeNode* root){
if(root->right==NULL && root->left==NULL){
m[root]=1;
return 1;
}
int c=1;
c+=root->right?m[root->right]:0;
if(root->left)
c+= c==1 ? m[root->left] : (m[root->right]>=m[root->left] ? 0 : (m[root->left]-m[root->right]));
m[root]=c;
return c;
}
bool isBalanced(TreeNode* root) {
if(root==NULL)
return true;
if( isBalanced(root->left) && isBalanced(root->right)){
int ldeep = root->left ? maxdeep(root->left) : 0;
int rdeep = root->right ? maxdeep(root->right) : 0;
if(abs(ldeep-rdeep)<=1)
return true;
}
return false;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def dfs(root):
if not root: return 0
ld=dfs(root.left)
if ld==-1: return -1
rd=dfs(root.right)
if rd==-1: return -1
return 1+max(ld,rd) if abs(ld-rd)<=1 else -1
return False if dfs(root)==-1 else True
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
剑指 Offer 57. 和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]
示例 2:
输入:nums = [10,26,30,31,47,60], target = 40
输出:[10,30] 或者 [30,10]
限制:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^6
题解
c++
哈希表
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> m;
for(int i:nums){
m[i]=1;
}
for(int i:nums){
if(m.find(target-i)!=m.end())
return {i,target-i};
}
return {};
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
python
双指针法
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
i,j=0,len(nums)-1
while target!=nums[i]+nums[j]:
if nums[i]+nums[j]>target:j-=1
else:i+=1
return [nums[i],nums[j]]
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
字典
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
m={}
for i in nums: m[i]=1
for i in nums:
if target-i in m: return[i,target-i]
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
剑指 Offer 57 - II. 和为s的连续正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
题解
c++
数学题不会做
滑动窗口
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
int i=1,j=2;
vector<vector<int>> ans;
while(i<j){
int tmp=(j+i)*(j-i+1)/2;
if(tmp>target)
i++;
else if(tmp<target)
j++;
else{
vector<int> cur;
for(int k=i;k<=j;k++){
cur.push_back(k);
}
ans.push_back(cur);
j++;
}
}
return ans;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def findContinuousSequence(self, target: int) -> List[List[int]]:
i,j=1,2
ans=[]
while i<j:
cur=(j+i)*(j-i+1)/2
if cur>target:i+=1
elif cur<target:j+=1
else:
tmp=[]
for k in range(i,j+1):
tmp.append(k)
ans.append(tmp)
i+=1
return ans
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 58 - I. 翻转单词顺序
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
示例 1:
输入: “the sky is blue”
输出: “blue is sky the”
示例 2:
输入: " hello world! "
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: “a good example”
输出: “example good a”
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
说明:
无空格字符构成一个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
题解
c++
倒序双指针暴力破解
class Solution {
public:
string reverseWords(string s) {
if(s.size()==0)
return s;
string ans;
int j=s.size()-1;
for(int i=s.size()-1;j>=i && i>=0;i--){
if(i==j && s[i]==' '){
j--;
}
else if(s[i]==' '){
ans.append(s,i+1,j-i);
ans.append(" ");
j=i-1;
}
else{
if(i==0){
ans.append(s,i,j-i+1);
}
}
}
while(ans.size()>0 && ans[ans.size()-1]==' ')
ans.erase(ans.size()-1);
return ans ;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
好吧,是我菜了!!
栈法
class Solution {
public:
string reverseWords(string s) {
stack<char> word;
string result = "";
for (int i = s.size() - 1; i >= 0; --i)
{
if (s[i] != ' ') //遇到单词则入栈
{
word.push(s[i]);
}
if (s[i] == ' ' || i == 0) //遇到空格或第一个字符都要检查一下栈中是否有单词可以弹出
{
bool flag = false; //标记是否发生出栈
while (word.empty() == false)
{
result.push_back(word.top()); //因为word栈存储的元素为char型,而result为string型,故不能相加,只能使用push_back()
word.pop();
flag = true;
}
if (flag)
{
result += " ";
}
}
}
return result.substr(0, result.size() - 1); //最后一个单词后面会多加一个空格
}
};
作者:wade-d
链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/solution/151-fan-zhuan-zi-fu-chuan-li-de-dan-ci-y-hn6y/
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
字符流
class Solution {
public:
string reverseWords(string s) {
istringstream istr(s); //istr以空格为分隔符把s分开
string result, word;
while(istr >> word) //分开得到的单词逐一拼接
result = word + ' ' + result;
return result.substr(0, result.size() - 1); //最后一个单词后面会多加一个空格
}
};
作者:wade-d
链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/solution/151-fan-zhuan-zi-fu-chuan-li-de-dan-ci-y-hn6y/
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”
限制:
1 <= k < s.length <= 10000
题解
c++
class Solution {
public:
string reverseLeftWords(string s, int n) {
char tmp;
while(n){
n--;
tmp=s[0];
s.erase(0,1);
s.append(1,tmp);
}
return s;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
class Solution {
public:
string reverseLeftWords(string s, int n) {
return s.substr(n,s.size())+s.substr(0,n);
}
};
三次翻转法
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(),s.begin()+n);
reverse(s.begin()+n,s.end());
reverse(s.begin(),s.end());
return s;
}
};
python
切片
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:]+s[:n]
- 时间复杂度 O(N): 其中 N 为字符串 s 的长度,字符串切片函数为线性时间复杂度(参考资料);
- 空间复杂度 O(N) : 两个字符串切片的总长度为 N
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
res = []
for i in range(n, n + len(s)):
res.append(s[i % len(s)])
return ''.join(res)
##############
###字符串不可变,效率低
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
res = ""
for i in range(n, n + len(s)):
res += s[i % len(s)]
return res
##############
剑指 Offer 59 - I. 滑动窗口的最大值
难度简单207收藏分享切换为英文接收动态反馈
给定一个数组 nums
和滑动窗口的大小 k
,请找出所有滑动窗口里的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
提示:
你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。
题解
c++
暴力法
c++优化了重复计算(暴力法请看python版)
好像优化的不好
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(nums.size()==0)
return {};
int cur_max=nums[0],i=0;
vector<int> ans;
while(i<nums.size() && i<k){
if(nums[i]>cur_max)
cur_max=nums[i];
i++;
}
ans.push_back(cur_max);
for(;i<nums.size();i++){
if(nums[i]>=cur_max){
ans.push_back(nums[i]);
cur_max=nums[i];
}
else{
if(nums[i-k]=cur_max){
cur_max=nums[i];
for(int j=i-k+1;j<i;j++){
if(nums[j]>cur_max)
cur_max=nums[j];
}
}
ans.push_back(cur_max);
}
}
return ans;
}
};
- 时间复杂度 O ( N ∗ k ) O(N*k) O(N∗k)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
return [ max(nums[i:i+k]) for i in range(0,len(nums)-k+1) ] if nums else []
- 时间复杂度 O ( N ∗ k ) O(N*k) O(N∗k)
- 空间复杂度 O ( 1 ) O(1) O(1)
单调队列解法
困难里补充这个代码8888
剑指 Offer 61. 扑克牌中的顺子
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例 1:
输入: [1,2,3,4,5]
输出: True
示例 2:
输入: [0,0,1,2,5]
输出: True
限制:
数组长度为 5
数组的数取值为 [0, 13] .
题解
不能有重复值(不包括大小王)
max-min<5
class Solution {
public:
bool isStraight(vector<int>& nums) {
unordered_map<int,int> m;
int max=-4,min=14;
for(int i:nums){
if(i!=0)
if(m.find(i)!=m.end())
return false;
else{
max=max>=i?max:i;
min=min<=i?min:i;
m[i]++;
}
}
return max-min<5;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
python
排序 遍历
class Solution:
def isStraight(self, nums: List[int]) -> bool:
num_0=0
nums.sort()
while not nums[num_0]:num_0+=1
for i in range(num_0,len(nums)-1):
if nums[i+1]==nums[i]:
return False
num_0-=nums[i+1]-nums[i]-1
return num_0>=0
- 时间复杂度 O ( N l o g ( N ) ) O(Nlog(N)) O(Nlog(N))
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 62. 圆圈中最后剩下的数字
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3
输出: 3
示例 2:
输入: n = 10, m = 17
输出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
题解
不会做!!!!!!!
解法:数学+递归
class Solution {
public:
int lastRemaining(int n, int m) {
if(n==1)
return 0;
int x=lastRemaining(n-1,m);
return (m+x)%n;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
python
迭代+数学
class Solution:
def lastRemaining(self, n: int, m: int) -> int:
cur=0
for i in range(2,n+1):
cur=(cur+m)%i
return cur;
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 65. 不用加减乘除做加法
异或保留,与进位, 与为空时就返回 不会!!!!!!!!!
留到和中等题的位运算一起做!!!!
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉搜索树中。
题解
c++
/**
* 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* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL)
return NULL;
if(root->val<p->val && root->val < q->val)
return lowestCommonAncestor(root->right,p,q);
if(root->val>p->val && root->val > q->val)
return lowestCommonAncestor(root->left,p,q);
return root;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
python
迭代版本
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
while root:
if root.val > p.val and root.val > q.val:root=root.left
elif root.val < p.val and root.val < q.val:root=root.right
else: break
return root;
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( 1 ) O(1) O(1)
剑指 Offer 68 - II. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中
题解
c++
递归
有一点难理解
/**
* 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* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL || p==root || q==root){
return root;
}
TreeNode* l=lowestCommonAncestor(root->left,p,q);
TreeNode* r=lowestCommonAncestor(root->right,p,q);
return l==NULL ? r : (r==NULL ? l:root);
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)