1.两个栈实现一个队列
题目描述:用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
分析:栈是先进后出,队列是先进先出
因此 push的话直接在stack1读入就好了
pop的话,需要从stack1压入stack2,再由stack2弹出
注意:若stack2是空的,需要从stack1向其压入数据
若stack2不空,则须stack2先弹出,空了之后,stack1压入
否则会影响元素弹出的位置
法1:
# 运行时间:25ms
# 占用内存:5724k
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if len(self.stack1) == 0 and len(self.stack2) == 0:
return
if len(self.stack2) == 0:
while len(self.stack1) != 0:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()``
法2
#运行时间:26ms 占用内存:5736k
class Solution:
def __init__(self):
self.stack1=[]
self.stack2=[]
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if self.stack2:
return self.stack2.pop()
else:
while(self.stack1):
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
2.旋转数组的最小值
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
借鉴大佬思路:二分法的变形,注意,若出现110111这样的,mid=high,只能high=high-1,挨个查找
#运行时间:665ms 占用内存:5852k
class Solution:
def minNumberInRotateArray(self, rotateArray):
low,high=0,len(rotateArray)-1
while low<high:
mid=(low+high)//2
if rotateArray[high]<rotateArray[mid]:
low=mid+1
elif rotateArray[high]>rotateArray[mid]:
high=mid
else:
high=high-1
return rotateArray[low]
c++版本
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if (rotateArray.empty()) return 0;
int left = 0, right = rotateArray.size() - 1;
while (left < right) {
//确认子数组是否是类似1,1,2,4,5,..,7的非递减数组
if (rotateArray[left] < rotateArray[right]) return rotateArray[left];
int mid = left + (right - left) / 2;
//如果左半数组为有序数组
if (rotateArray[left] < rotateArray[mid])
left = mid + 1;
//如果右半数组为有序数组
else if (rotateArray[mid] < rotateArray[right])
right = mid;
//否则,rotateArray[left] == rotateArray[mid] == rotateArray[right]
else {
++left;
}
}
return rotateArray[left];
}
};
3.二维数组中的查找
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:矩阵有序,所以从左下角进行查找,若>目标值,向上一行,<目标值,向右一行,时间复杂度O(M+N)
注:python二维数组行列长度获取 输出行列array.shape
行:array.shape[0],列:array.shape[1]
class Solution:
#array 二维列表
def Find(self, target, array):
row=len(array)
col=len(array[0])
i,j=row-1,0
while i>=0 and j<col:
if array[i][j]==target:
return True
elif array[i][j]>target:
i=i-1
else:
j=j+1
return False
4.数组中的重复数字
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
大佬的思路:将数组保存为哈希表,然后再遍历依次即可。哈希表的查找时间是O(1),但需要额外的存储空间。不知道为什么测试没有通过
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
if numbers == None:
return None
count.dict={
}
for num im numbers:
count_dict[num]=count_dict.get(num,0)+1
for num in numbers:
if count_dict[num]>1:
duplication[0]=num
return True
return False
大佬做法2:直接利用sort()函数进行排序,不知道算不算作弊操作
class Solution:
#这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
numbers.sort() #sort对数组进行排序
for i in range(len(numbers)-1):
if numbers[i] == numbers[i+1]:
duplication[0]=numbers[i]
return True
return False
5.数在排序数组中出现的速度
思路1:遍历
class Solution:
def GetNumberOfK(self, data, k):
count=0
for num in data:
if num==k:
count +=1
return count
思路2:利用二分法,找到k的最左边和最右边对应的位置,相减
代码待补充
6.替换空格
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
大佬思路:先遍得到空格数count
再从后往前,遇到非空格往后挪count2个位置
遇到空格,该位置后移2(count-1)个位置,其它依次
class Solution {
public:
void replaceSpace(char *str,int length) {
int count=0;
for(int i=0;i<length;i++){
if(str[i]==' ')
count++;
}
for(int i=length-1;i>=0;i--){
if(str[i]!=' '){
str[i+2*count]=str[i];
}
else{
count--;
str[i+2*count]='%';
str[i+2*count+1]='2';
str[i+2*count+2]='0';
}
}
}
};
7.二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
补码的表示方法是:正数的补码就是其本身,负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
大佬思路:
一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。(负数用补码表示,所以是一样的道理)
class Solution {
public:
int NumberOf1(int n) {
int count=0;
if(n==0){
return 0;}
while(n!=0){
count++;
n=n & n-1;
}
return count;
}
};
8.写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号
两个数异或:相当于每一位相加,而不考虑进位;
两个数相与,并左移一位:相当于求得进位;
将上述两步的结果相加
13+11 = ?;
13 的二进制 1 1 0 1 -----a 13
11 的二进制 1 0 1 1 -----b 11
(a&b) <<1 -> 1 0 0 1 0 -----d 18
a^b -> 0 1 1 0 -----e 6
(d&e) <<1 -> 0 0 1 0 0 ------f 4
d^e -> 1 0 1 0 0 -----g 20
(f&g) <<1 -> 0 1 0 0 0 ------h 8
f^g -> 1 0 0 0 0 ------i 16
(h&i) <<1 -> 0 0 0 0 0 ------h 0 ---- --------退出循环
h^i -> 1 1 0 0 0 ------i 24
#递归
#4ms
class Solution {
public:
int Add(int num1, int num2)
{
if(num2==0)
return num1;
return Add(num1^num2, (num1&num2)<<1);
}
};
法2:迭代
//3ms
class Solution {
public:
int Add(int num1, int num2)
{
while(num2!=0){
int sum1=num1^num2;
int sum2=(num1&num2)<<1;
num1=sum1;
num2=sum2;
}
return num1;
}
9.设计一个函数, 可以将任意十进制的数, 转换成任意2到9的进制表示的形式
需要转换的数字x(0<=x<=1e18) 转换使用的进制k(2<=k<=9)
#include <bits/stdc++.h>
using namespace std;
int main(){
long x;
int k;
cin>>x>>k;
stack<int> s;
if(x==0)
cout<<0<<endl;
else{
while(x){
s.push(x%k);
x /= k;
}
while(!s.empty()){
cout<<s.top();
s.pop();
}
cout<<endl;
}
return 0;
}
10 跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
思路:第n阶可以从n-2阶跳,也可以用n-1阶跳。
所以:f(n)=f(n-1)+f(n-1) 斐波那契数列
#注意初始条件
#迭代
class Solution {
public:
int jumpFloor(int number) {
if(number==0){
return 0;}
if(number==1){
return 1;}
if(number==2){
return 2;}
int prenum=2;
int preprenum=1;
int result=0;
for(int i=3;i<=number;i++){
result=prenum+preprenum;
preprenum=prenum;
prenum=result;
}
return result;
}
10.变态版跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
分析:大佬的思路:
每个台阶可以看作一块木板,让青蛙跳上去,n个台阶就有n块木板,最后一块木板是青蛙到达的位子, 必须存在,其他 (n-1) 块木板可以任意选择是否存在,则每个木板有存在和不存在两种选择,(n-1) 块木板 就有 [2^(n-1)] 种跳法,可以直接得到结果。
class Solution {
public:
int jumpFloorII(int number) {
return 1<<(number-1); //用位移运算做2^(n-1),速度更快
}
};
因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
跳1级,剩下n-1级,则剩下跳法是f(n-1)
跳2级,剩下n-2级,则剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+…+f(1)
因为f(n-1)=f(n-2)+f(n-3)+…+f(1)
所以f(n)=2*f(n-1)
迭代
链表
11.寻找链表的倒数第k个节点
思路:定义两个指针,快的先跑k步然后快慢一起跑,快的到空的时候,慢指针就在倒数第k个节点
时间复杂度O(n),空间复杂度O(1)
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead == nullptr || k < 1){
return nullptr;
}
ListNode *pre = pListHead;
ListNode *last = pListHead;
while(k > 0){
if(last == nullptr){
return nullptr;
}
last = last->next;
k--;
}
while(last != nullptr){
last = last->next;
pre = pre->next;
}
return pre;
}
};
删除倒数第k个节点
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head==nullptr || n<1){
return nullptr;
}
ListNode* pre=head;
ListNode* last=head;
while(n>0){
if(last==nullptr){
return nullptr;
}
last=last->next;
n--;
}
//当n=链表的长度时,直接删除头节点,返回head->next
if(!last){
return head -> next;
}
while(last->next!=nullptr){
//这样找出来的pre为第k+1个节点
last=last->next;
pre=pre->next;
}
pre->next=pre->next->next;
return head;
}
};
12,合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
//递归法
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode* node=NULL;
if(pHead1==NULL){
return node=pHead2;}
if(pHead2==NULL){
return node=pHead1;}
if(pHead1->val<pHead2->val){
node=pHead1;
node->next=Merge(pHead1->next,pHead2);
}else
{
node=pHead2;
node->next=Merge(pHead1,pHead2->next);
}
return node;
}
};
//非递归
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode *p = new ListNode(0);
ListNode *head = p;
while (pHead1 && pHead2)
{
if (pHead1->val < pHead2->val)
{
head->next = pHead1;
pHead1 = pHead1->next;
}
else
{
head->next= pHead2;
pHead2 = pHead2->next;
}
head = head->next;
}
if (pHead1)
head->next = pHead1;
if (pHead2)
head->next = pHead2;
return p->next;
}
};
13.链表反转
//头插法
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* root=new ListNode(0);
ListNode* next=NULL;
while(pHead!=NULL){
next=pHead->next;
pHead->next=root->next; //将根节点的后继变成pHead的后继
root->next=pHead;//将pHead的值给根结点的后继
pHead=next;
}
return root->next;
}
//依次反转法(三个指针)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre=NULL;
ListNode* curr=head;
while(curr!=NULL){
ListNode* next=curr->next;//保存后节点的值
curr->next=pre;
pre=curr; //前指针后移一步
curr=next;//当前指针后移一步
}
return pre;
}
};
//递归的方法其实是非常巧的,它利用递归走到链表的末端,
//然后再更新每一个node的next 值 ,实现链表的反转。
//而newhead 的值没有发生改变,为该链表的最后一个结点
//所以,反转后,我们可以得到新链表的head。
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
//如果链表为空或者链表中只有一个元素
if(pHead==NULL||pHead->next==NULL) return pHead;
//先反转后面的链表,走到链表的末端结点
ListNode* pReverseNode=ReverseList(pHead->next);
//再将当前节点设置为后面节点的后续节点
pHead->next->next=pHead;
pHead->next=NULL;
return pReverseNode;
}
};
14.从尾到头打印链表
//利用栈先进后出的特性
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> value;
stack<int> stk;
ListNode* p=NULL;
p=head;
while(p!=NULL){
stk.push(p->val);
p=p->next;
}
while(!stk.empty()){
value.push_back(stk.top());
stk.pop();
}
return value;
}
};
//递归
class Solution {
public:
vector<int> value;
vector<int> printListFromTailToHead(ListNode* head) {
if(head!=NULL){
if(head->next!=NULL){
value=printListFromTailToHead(head->next);
}
value.push_back(head->val);
}
return value;
}
};
15.找两个链表的第一个公共节点
思路:若有公共节点,公共节点长度为c
则:A=a+c;B=b+c;
当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode* l1=pHead1;
ListNode* l2=pHead2;
while(l1!=l2){
//当l1和l2相等时,证明到了第一个公共节点,退出循环,返回当前的l1或l2
l1=(l1==NULL)? pHead2:l1->next;
l2=(l2==NULL)? pHead1:l2->next;
}
return l1;
16 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次
思路1:递归套路解决链表问题:
找终止条件:当head指向链表只剩一个元素的时候,自然是不可能重复的,因此return
想想应该返回什么值:应该返回的自然是已经去重的链表的头节点
每一步要做什么:宏观上考虑,此时head.next已经指向一个去重的链表了,而根据第二步,我应该返回一个去重的链表的头节点。因此这一步应该做的是判断当前的head和head.next是否相等,如果相等则说明重了,返回head.next,否则返回head
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head==