1.二叉树镜像
python:
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
if root == None:
return
self.Mirror(root.left)
self.Mirror(root.right)
root.left,root.right = root.right,root.left
C++:
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if (pRoot) {
Mirror(pRoot->left);
Mirror(pRoot->right);
TreeNode *temp=pRoot->left;
pRoot->left=pRoot->right;
pRoot->right=temp;
}
}
};
2.判断链表中是否包含环,输出环入口节点,否则输出NULL
思路:
该题使用一种巧妙的方法,使用两个步长分别是1和2的指针
python
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
if pHead== None or pHead.next == None:
return None
fast = slow = pHead
while(fast and fast.next):
slow = slow.next
fast = fast.next.next
if slow == fast:
fast = pHead
while(fast!=slow):
fast = fast.next
slow = slow.next
return fast
return None
C++
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if ((pHead->next==NULL)||(pHead==NULL)) return NULL;
ListNode* fast = pHead;
ListNode* slow = pHead;
bool isCycle = false;
while((fast!=NULL)&&(slow!=NULL)){
fast=fast->next;
slow=slow->next;
if (fast->next==NULL)return NULL;
fast=fast->next;
if(fast==slow){isCycle=true;break;}
}
if(!isCycle)return NULL;
fast=pHead;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return fast;
}
};
3.删除链表重复节点
python
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplication(self, pHead):
# write code here
if(pHead==None):
return None
if(pHead.next==None):
return pHead
val = pHead.val
p = pHead.next
if(val!=p.val):
pHead.next=self.deleteDuplication(p)
return pHead
else:
while (p and (val==p.val)):
p=p.next
return self.deleteDuplication(p)
c++
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if (!pHead) return 0;
if (!pHead->next) return pHead;
int val = pHead->val;
ListNode* p = pHead->next;
if (p->val != val) {
pHead->next = deleteDuplication(p);
return pHead;
} else {
while (p && p->val == val) p = p->next;
return deleteDuplication(p);
}
}
};
4.反转链表
使用python array与c++ STL自带的reverse函数即可
python
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
ret = []
head = listNode
while(head):
ret.append(head.val)
head = head.next
ret.reverse()
return ret
c++
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> myvector;
while(head!=NULL){myvector.push_back(head->val);head=head->next;}
reverse(myvector.begin(),myvector.end());
return myvector;
}
};
5.斐波那契数列
python
# -*- coding:utf-8 -*-
class Solution:
def Fibonacci(self, n):
# write code here
if n==0:
return 0;
elif n==1:
return 1;
else:
a0=0;
a1=1;
for i in range(n-1):
a2=a0+a1;
a0=a1;
a1=a2;
return a2
C++
class Solution {
public:
int Fibonacci(int n) {
if (n ==0) return 0;
else if(n == 1) return 1;
else{
int a0 = 0;
int a1 = 1;
int a2;
for (int i=0;i<n-1;i++){
a2 = a0 + a1;
a0 = a1;
a1 = a2;
}
return a2;
}
}
};
6.青蛙跳台阶,一次跳1或2阶,共n阶,几种跳法
思路:
f(1)=1
f(2)=2
…
f(n)=f(n-1)+f(n-2)
注意:递归效率低,重复调用函数,尽量使用迭代。
python
# -*- coding:utf-8 -*-
class Solution:
def jumpFloor(self, number):
# write code here
if number==1:
return 1
elif number==2:
return 2
else:
a0=1
a1=2
for i in range(number-2):
a2=a0+a1
a0=a1
a1=a2
return a2
c++
class Solution {
public:
int jumpFloor(int number) {
if (number==0)return 0;
else if (number==1)return 1;
else if (number==2)return 2;
else
return jumpFloor(number-1)+jumpFloor(number-2);
}
};
7.变态跳台阶,一次可以跳1~n阶
思路:
f(1)=1
f(2)=f(1)+1
f(3)=f(2)+f(1)+1=2*f(2)
…
f(n)=2*f(n-1)
python
# -*- coding:utf-8 -*-
class Solution:
def jumpFloorII(self, number):
# write code here
a0=1
for i in range(number-1):
a0=a0*2
return a0
C++
class Solution {
public:
int jumpFloorII(int number) {
int a0 = 1;
for(int i=0;i<number-1;i++){
a0=a0*2;
}
return a0;
}
};
8.矩阵覆盖
用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法
思路:依旧斐波那契
python
# -*- coding:utf-8 -*-
class Solution:
def rectCover(self, number):
# write code here
if number==1:
return 1
elif number==2:
return 2
elif number==0:
return 0
else:
a0=1
a1=2
for i in range(number-2):
a2=a0+a1
a0=a1
a1=a2
return a2
c++
class Solution {
public:
int rectCover(int number) {
if(number==1)return 1;
else if(number==2)return 2;
else if(number==0)return 0;
else{
int a0=1;
int a1=2;
int a2;
for(int i=0;i<number-2;i++){
a2=a0+a1;
a0=a1;
a1=a2;
}
return a2;
}
}
};
9.字符串转整数
将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
python
# -*- coding:utf-8 -*-
class Solution:
def StrToInt(self, s):
# write code here
symbol=1
num=0
if s=='':
return 0
for i in s:
if i=='+':
symbol=1
elif i=='-':
symbol=-1
elif i>'0' and i<'9':
num=num*10+int(i)
else:
return 0
return symbol*num
c++
class Solution {
public:
int StrToInt(string str) {
int symbol = 1;
int num=0;
for (int i=0;i<str.size();i++){
if (str[i]=='+')symbol=1;
else if(str[i]=='-')symbol=-1;
else if((str[i]>'0')&&(str[i]<'9'))num=num*10+(str[i]-'0');
else return 0;
}
return symbol*num;
}
};
10.平衡二叉树的判断
思路:BST的定义为|height(lefttree)−height(righttree)|<=1且两个子树均为BST,原问题拆分为计算树高度和判断高度差
python
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def IsBalanced_Solution(self, pRoot):
# write code here
if pRoot==None:
return True
h1=self.Get_Tree_Height(pRoot.left)
h2=self.Get_Tree_Height(pRoot.right)
if(h1-h2)<=1 and(h2-h1)<=1:
return True
else:
return False
def Get_Tree_Height(self, pRoot):
if pRoot==None:
return 0
else:
return max(self.Get_Tree_Height(pRoot.left),self.Get_Tree_Height(pRoot.right))+1
c++
class Solution {
public:
int TreeDepth(TreeNode *pRoot)
{
if (pRoot == NULL)
return 0;
int left = TreeDepth(pRoot->left);
int right = TreeDepth(pRoot->right);
return (left > right) ? (left + 1) : (right + 1);
}
bool IsBalanced_Solution(TreeNode* pRoot) {
if (pRoot == NULL)
return true;
int left = TreeDepth(pRoot->left);
int right = TreeDepth(pRoot->right);
int diff = left - right;
if (diff > 1 || diff < -1)
return false;
return IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right);
}
};
11.和为S的连续正数序列
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
思考:S%奇数==0 或者S%偶数==偶数/2 就说明有这个连续序列,但是注意是正数序列,可能会出现越界情况
python
# -*- coding:utf-8 -*-
class Solution:
def FindContinuousSequence(self, tsum):
# write code here
k = 2
ret = []
for k in range(2,tsum):
if k%2==1 and tsum%k==0:
tmp = []
mid = tsum/k
if mid-k/2>0:
for i in range(mid-k/2,mid+k/2+1):
tmp.append(i)
ret.append(tmp[:])
elif k%2==0 and (tsum%k)*2==k:
mid = tsum/k
tmp = []
if mid-k/2+1>0:
for i in range(mid-k/2+1,mid+k/2+1):
tmp.append(i)
ret.append(tmp[:])
ret.sort()
return ret
c++
class Solution {
public:
vector<vector<int> > FindContinuousSequence(int sum) {
int l = 1,r = 1,sumx = 1;
vector<vector<int> > ans;
while(l <= r){
r ++;
sumx += r;
while(sumx > sum){
sumx -= l;
l ++;
}
if(sumx == sum && l != r){
vector<int> tmp;
for(int i = l;i <= r;i ++) tmp.push_back(i);
ans.push_back(tmp);
}
}
return ans;
}
};
12.左旋转字符串
对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。
python
# -*- coding:utf-8 -*-
class Solution:
def LeftRotateString(self, s, n):
# write code here
if s=='':
return s
mov=n%len(s)
news=s[mov:]+s[:mov]
return news
c++
class Solution {
public:
string LeftRotateString(string str, int n) {
int lstr=str.size();
if (lstr==0)return str;
int mov=n%lstr;
string newstr;
for(int i = mov;i<lstr;i++)newstr.push_back(str[i]);
for(int i = 0;i<mov;i++)newstr.push_back(str[i]);
return newstr;
}
};
13.数字在排序数组中出现的次数
思路:二分查找
python
# -*- coding:utf-8 -*-
class Solution:
def GetNumberOfK(self, data, k):
# write code here
start = 0
end = len(data)-1
while(start<=end):
mid = (start+end)/2
if data[mid]==k:
cnt = 0
tmp = mid
while(tmp>=0 and data[tmp]==k):
cnt+=1
tmp-=1
tmp = mid+1
while(tmp<len(data) and data[tmp]==k):
cnt+=1
tmp+=1
return cnt
elif data[mid]>k:
end = mid-1
else:
start = mid+1
return 0
C++
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
if(data.size()==0)return 0;
int len=data.size();
int KeyIndex=0;
KeyIndex=BinarySearch(data,0,len-1,k);
if(KeyIndex==-1) return 0;
int sumber=1;
int m=KeyIndex-1;
int n=KeyIndex+1;
while(m>=0&&data[m]==k)
{
m--;sumber++;
}
while(n<len&&data[n]==k)
{
n++; sumber++;
}
return sumber;
}
int BinarySearch(vector<int> data, int low, int high, int k){
while (low<=high){
int m = (high + low) / 2;
if (data[m] == k)return m;
else if (data[m] < k) low = m+ 1;
else high = m - 1;}
return -1;
}
};
14.数组中只出现一次的数字
思路:在其他题目中,要求时间复杂度为O(n),排除先排序;空间复杂度要求O(1),排除hash思路。考虑到对于一个int类型变量a,a与0的异或为本身,与自身的异或为0,因此可以将所有数字依次异或,这样偶数次数的数字被消除,仅剩一次的数字。但本题中有两个这样的数字,因此需要将两个数字分离成两堆。在将所有数字异或后,所得结果即所求两个数字的异或值,因此可从两个数字的异或值中第一位不是0的位出手,将所有数字根据此位是否为1分为两堆,两堆分别求异或值结果即所求两数。
python
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, array):
# write code here
ans,a1,a2,flag= 0,0,0,1
for num in array:
ans = ans ^ num
while(ans):
if ans%2 == 0:
ans = ans >>1
flag = flag <<1
else:
break
for num in array:
if num & flag:
a1 = a1 ^ num
else:
a2 = a2 ^ num
return a1,a2
c++
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if (data.size() < 2)
return;
int resultExclusiveOR = 0;
for (int i = 0; i < data.size(); ++ i)
resultExclusiveOR ^= data[i];
unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);
*num1 = *num2 = 0;
for (int j = 0; j < data.size(); ++ j){
if(IsBit1(data[j], indexOf1))
*num1 ^= data[j];
else
*num2 ^= data[j];
}
}
unsigned int FindFirstBitIs1(int num){
int indexBit = 0;
while (((num & 1) == 0) && (indexBit < 32)){
num = num >> 1;
indexBit++;}
return indexBit;
}
bool IsBit1(int num, unsigned int indexBit){
num = num >> indexBit;
return (num & 1);}
};
15.翻转单词顺序列
将句子中由空格间隔的各词汇顺序翻转。
python
# -*- coding:utf-8 -*-
class Solution:
def ReverseSentence(self, s):
# write code here
ret = s.split(" ")
ret.reverse()
return ' '.join(ret)
c++
class Solution {
public:
string ReverseSentence(string str) {
int len = str.size();
int start = 0;
for(int i = 0; i < len; i ++){
if(str[i] == ' '){
reverse(str.begin()+start, str.begin()+i);
start = i+1;
}
if(i == len-1){
reverse(str.begin()+start, str.end());
}
}
reverse(str.begin(), str.end());
return str;
}
};
16.二叉树深度
python
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def TreeDepth(self, pRoot):
# write code here
if(pRoot==None):
return 0
h1 = self.TreeDepth(pRoot.left);
h2 = self.TreeDepth(pRoot.right);
if h1>h2:
return h1+1
else:
return h2+1
c++
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
int TreeDepth(TreeNode* pRoot)
{
if (pRoot==NULL)return 0;
int depth1 = TreeDepth(pRoot->left);
int depth2 = TreeDepth(pRoot->right);
int depth = (depth1 > depth2 ? depth1 : depth2)+1;
return depth;
}
};
17.和为S的两个数字
输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
思路:采用两个指针分别从数组两端向中间推进,最先满足条件的两个数乘积最小。
python
# -*- coding:utf-8 -*-
class Solution:
def FindNumbersWithSum(self, array, tsum):
# write code here
a1=0
a2=-1
while(a1-a2<len(array)):
if(array[a1]+array[a2]<tsum):
a1+=1
elif(array[a1]+array[a2]>tsum):
a2-=1
else:
return [array[a1],array[a2]]
return[]
c++
class Solution {
public:
vector<int> FindNumbersWithSum(vector<int> array,int sum) {
int len = array.size();
vector<int>twonum;
if (len<=1)return twonum;
int v1=0,v2=len-1;
while(v1!=v2){
if((array[v1]+array[v2])<sum)v1++;
else if((array[v1]+array[v2])>sum)v2--;
else {twonum.push_back(array[v1]);twonum.push_back(array[v2]);break;}
}
return twonum;
}
};
18.顺时针打印矩阵
python
# -*- coding:utf-8 -*-
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
m=len(matrix)
ans=[]
if m==0:
return ans
n=len(matrix[0])
w1=0;w2=n-1;h1=0;h2=m-1;
while(True):
if((w1>w2)or(h1>h2)):
break;
for i in range(w1,w2+1):
ans.append(matrix[h1][i])
h1=h1+1
if((w1>w2)or(h1>h2)):
break;
for i in range(h1,h2+1):
ans.append(matrix[i][w2])
w2=w2-1
if((w1>w2)or(h1>h2)):
break;
for i in range(w1,w2+1):
ans.append(matrix[h2][n-2-i])
h2=h2-1
if((w1>w2)or(h1>h2)):
break;
for i in range(h1,h2+1):
ans.append(matrix[m-1-i][w1])
w1=w1+1
return ans
c++
class Solution {
public:
vector<int> printMatrix(vector<vector<int>> matrix) {
int row=matrix.size();
int col=matrix[0].size();
vector<int> result;
if(row==0||col==0)
return result;
int left=0,right=col-1,top=0,btm=row-1;
while(left<=right&&top<=btm)
{
for(int i=left;i<=right;i++)
result.push_back(matrix[top][i]);
if(top<btm)
for(int i=top+1;i<=btm;i++)
result.push_back(matrix[i][right]);
if(top<btm&&left<right)
for(int i=right-1;i>=left;i--)
result.push_back(matrix[btm][i]);
if(top+1<btm&&left<right)
for(int i=btm-1;i>=top+1;i--)
result.push_back(matrix[i][left]);
left++;right--;top++;btm--;
}
return result;
}
};
19.二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:中序遍历,根据其是否含有右子树、若无则返回父节点等系列条件判断
python
class Solution:
def GetNext(self, pNode):
# write code here
# left root right
if pNode == None:
return None
if pNode.right:
tmp = pNode.right
while(tmp.left):
tmp = tmp.left
return tmp
p = pNode.next
while(p and p.right==pNode):
pNode = p
p = p.next
return p
c++
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode->right!=NULL){
TreeLinkNode *temp=pNode->right;
while(temp->left!=NULL)temp=temp->left;
return temp;
}
else{
TreeLinkNode *temp=pNode;
while(temp->next!=NULL){
if(temp==temp->next->left)return temp->next;
else{temp=temp->next;}
}
return NULL;
}
}
};
20.对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
思路:递归
python
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetrical(self, pRoot):
# write code here
if pRoot==None:
return True
return self.isSame(pRoot.right,pRoot.left)
def isSame(self,t_left,t_right):
if(t_left==None)and(t_right==None):
return True
elif(t_left!=None)and(t_right==None):
return False
elif(t_left==None)and(t_right!=None):
return False
else:
result = True
result = result and self.isSame(t_left.left,t_right.right)
result = result and self.isSame(t_left.right,t_right.left)
result = result and (t_left.val==t_right.val)
return result
C++
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
return isSymmetrical(pRoot,pRoot);
}
bool isSymmetrical(TreeNode* pRoot1,TreeNode* pRoot2)
{
if(pRoot1==nullptr&&pRoot2==nullptr)
return true;
if(pRoot1==nullptr||pRoot2==nullptr)
return false;
if(pRoot1->val!=pRoot2->val)
return false;
return isSymmetrical(pRoot1->left,pRoot2->right)&& isSymmetrical(pRoot1->right,pRoot2->left);
}
};
21.逐行打印二叉树
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
思路:此题在于灵活使用队列这一数据结构。将本层的结点全部push后,记录结点数目,每打印一个结点就pop一个,同时将该节点的左右子树结点push。在c++中,使用queue数据结构。在python中,则使用列表的append、pop(0)。
python
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
if not pRoot:
return []
res=[]
tmp=[pRoot]
while tmp:
size=len(tmp)
row=[]
for i in tmp:
row.append(i.val)
res.append(row)
for i in range(size):
node=tmp.pop(0)
if node.left:
tmp.append(node.left)
if node.right:
tmp.append(node.right)
return res
c++
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int>>result;
if(pRoot==NULL)return result;
queue<TreeNode*>q;
q.push(pRoot);
while(q.size()!=0){
int len=q.size();
vector<int>c;
for(int i=0;i<len;i++){
TreeNode *t = q.front();
q.pop();
c.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
result.push_back(c);
}
return result;
}
};
22.之字形打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
思路:在按行打印二叉树基础上添加一行reverse即可。
python
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Print(self, pRoot):
if not pRoot :return []
layers = [[pRoot,]]
while layers[-1] != []:
layer = []
for root in layers[-1]:
if root.left != None:
layer.append(root.left)
if root.right != None:
layer.append(root.right)
layers.append(layer)
ret = []
for i,layer in enumerate(layers[:-1]):
layer_values = [root.val for root in layer]
if i%2 == 1 :
ret.append(layer_values[::-1])
else:
ret.append(layer_values)
return ret
c++
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int>>result;
if(pRoot==NULL)return result;
queue<TreeNode*>q;
q.push(pRoot);
bool rev=false;
while(q.size()!=0){
int len=q.size();
vector<int>c;
for(int i=0;i<len;i++){
TreeNode *t = q.front();
q.pop();
c.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
if(rev)reverse(c.begin(),c.end());
rev=!rev;
result.push_back(c);
}
return result;
}
};
23.序列化与反序列化二叉树
序列化即按照一定的遍历方式如前序、中序、后序、按层等,将二叉树转换为字符串。空节点以’#’方式保存。反序列化即按照序列化的遍历方式,将字符串重新转换为内存中树的形式。
思路:按照前序遍历方式,通过递归实现。
python
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Serialize(self, root):
# write code here
def doit(node):
if node:
vals.append(str(node.val))
doit(node.left)
doit(node.right)
else:
vals.append('#')
vals = []
doit(root)
return ' '.join(vals)
def Deserialize(self, s):
# write code here
def doit():
val = next(vals)
if val == '#':
return None
node = TreeNode(int(val))
node.left = doit()
node.right = doit()
return node
vals = iter(s.split())
return doit()
C++(存疑)
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
private:
TreeNode* decode(char *&str) {
if(*str=='#'){
str++;
return NULL;
}
int num = 0;
while(*str != ',')
num = num*10 + (*(str++)-'0');
str++;
TreeNode *root = new TreeNode(num);
root->left = decode(str);
root->right = decode(str);
return root;
}
public:
char* Serialize(TreeNode *root) {
if(!root) return "#";
string r = to_string(root->val);
r.push_back(',');
char *left = Serialize(root->left);
char *right = Serialize(root->right);
char *ret = new char[strlen(left) + strlen(right) + r.size()];
strcpy(ret, r.c_str());
strcat(ret, left);
strcat(ret, right);
return ret;
}
TreeNode* Deserialize(char *str) {
return decode(str);
}
};
24.数据流中的中位数
使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路:注意python与c++中的成员变量的定义方式、sort函数的使用
python
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.data=[]
def Insert(self, num):
# write code here
self.data.append(num)
self.data.sort()
def GetMedian(self,data):
# write code here
length=len(self.data)
if length%2==0:
return (self.data[length//2]+self.data[length//2-1])/2.0
else:
return self.data[int(length//2)]
c++
class Solution
{
vector<int> number;
public:
void Insert(int num)
{
number.push_back(num);
}
double GetMedian()
{
sort(number.begin(),number.end());
if(number.size() % 2 == 1)
{
return (double)(number[number.size()/2]);
}
else
{
return (double)((double)((number[(number.size()/2)-1])+(number[number.size()/2]))/2);
}
}
};
25.二叉搜索树的第k个节点
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
思路:考虑到二叉搜索树(BST)中,中序遍历的结果即有序数组。
python
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回对应节点TreeNode
# def __ini__(self):
# self.data=[]
def KthNode(self, pRoot, k):
# write code here
if pRoot==None:
return None
global data
data = []
self.Traver(pRoot)
if k>len(data) or k<=0:
return None
return data[k-1]
def Traver(self, pRoot):
if pRoot==None:
return None
self.Traver(pRoot.left)
data.append(pRoot)
self.Traver(pRoot.right)
c++
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
TreeNode* KthNode(TreeNode* root, int k)
{
TreeNode *res = NULL;
int c = 0;
inorder(root, &res, k, &c);
return res;
}
void inorder(TreeNode* root, TreeNode **res, int k, int *c)
{
if (root)
{
inorder(root -> left, res, k, c);
++*c;
if (*c == k) *res = root;
inorder(root -> right, res, k, c);
}
}
};
26.重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:采用递归,根据前序遍历中根节点位于首位,在中序遍历中找出,将前序遍历、中序遍历的左右子树序列递归处理。
python
class Solution(object):
def reConstructBinaryTree(self, pre, tin):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if pre==[]:
return None
val = pre[0]
idx = tin.index(val)
ltin = tin[0:idx]
rtin = tin[idx+1:]
lpre = pre[1:1+len(ltin)]
rpre = pre[1+len(ltin):]
root = TreeNode(val)
root.left = self.reConstructBinaryTree(lpre,ltin)
root.right = self.reConstructBinaryTree(rpre,rtin)
return root
C++
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
int veclen = pre.size();
if (veclen==0)return NULL;
vector<int>preleft,preright,vinleft,vinright;
TreeNode* head=new TreeNode(pre[0]);
int gen = 0;
for(int i=0;i<veclen;i++){
if(vin[i]==pre[0]){
gen=i;
break;
}
}
for (int i = 0;i<gen;i++){
vinleft.push_back(vin[i]);
preleft.push_back(pre[i+1]);
}
for (int i = gen+1;i<veclen;i++){
vinright.push_back(vin[i]);
preright.push_back(pre[i]);
}
head->left=reConstructBinaryTree(preleft,vinleft);
head->right=reConstructBinaryTree(preright,vinright);
return head;
}
};
27.滑动窗口的最大值
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
python
# -*- coding:utf-8 -*-
class Solution:
def maxInWindows(self, num, size):
# write code here
if size == 0:
return []
ret = []
stack = []
for pos in range(len(num)):
while (stack and stack[-1][0] < num[pos]):
stack.pop()
stack.append((num[pos], pos))
if pos>=size-1:
while(stack and stack[0][1]<=pos-size):
stack.pop(0)
ret.append(stack[0][0])
return ret
c++
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int>result;
if((num.size()<1)||(size<1))return result;
if(num.size()<size)return result;
for (int i=0;i<(num.size()-size+1);i++){
int m=num[i];
for(int j=i+1;j<i+size;j++){
if(num[j]>m)m=num[j];
}
result.push_back(m);
}
return result;
}
};
28.用两个栈实现队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路:注意c++的STL中的stack,top()和pop()的区别。
python
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1=[]
self.stack2=[]
def push(self, node):
# write code here
while(len(self.stack2)):
self.stack1.append(self.stack2.pop());
self.stack1.append(node)
def pop(self):
# return xx
while(len(self.stack1)):
self.stack2.append(self.stack1.pop());
return self.stack2.pop()
c++
class Solution
{
public:
void push(int node) {
while(stack2.size()){
stack1.push(stack2.top());
stack2.pop();
}
stack1.push(node);
}
int pop() {
while(stack1.size()){
stack2.push(stack1.top());
stack1.pop();}
int temp=stack2.top();
stack2.pop();
return temp;
}
private:
stack<int> stack1;
stack<int> stack2;
};
29.旋转数组最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
python
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray)==0:
return 0
result = rotateArray[0]
for i in range(len(rotateArray)-1):
if rotateArray[i]>rotateArray[i+1]:
result=rotateArray[i+1]
break
return result
c++
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if (rotateArray.size()==0)return 0;
int result=rotateArray[0];
for(int i=0;i<rotateArray.size()-1;i++){
if(rotateArray[i]>rotateArray[i+1]) {
result=rotateArray[i+1];
break;}
}
return result;
}
};
30.丑数
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:若从1开始,每个数判断是否只有2,3,5三个质因数,则时间复杂度太高。因此考虑牺牲一部分空间,保存前K个丑数,则下一个丑数必定是前面某个丑数乘2或3或5所得,因此只需将现有丑数乘2、3、5后除去已有丑数,再选择最小数加入丑数list后对list排序即可。下述c++方法更加巧妙,有待深究。
python:
# -*- coding:utf-8 -*-
class Solution:
def GetUglyNumber_Solution(self, index):
# write code here
if index<1:
return 0
result=[1,2,3,4,5]
while(index>len(result)):
result=self.addnum(result)
return result[index-1]
def addnum(self, result):
a1=set([b*2 for b in result]+[b*3 for b in result]+[b*5 for b in result])
a2=a1-set(result)
a2=list(a2)
a2.sort()
result.append(a2[0])
result.sort()
return result
c++
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if (index < 7)return index;
vector<int> res(index);
res[0] = 1;
int t2 = 0, t3 = 0, t5 = 0, i;
for (i = 1; i < index; ++i)
{
res[i] = min(res[t2] * 2, min(res[t3] * 3, res[t5] * 5));
if (res[i] == res[t2] * 2)t2++;
if (res[i] == res[t3] * 3)t3++;
if (res[i] == res[t5] * 5)t5++;
}
return res[index - 1];
}
};
31.两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共结点。
思路:两个链表既然有公共部分,则必然从第一个公共节点往后全部相同,因此可以先求出两个链表长度,去掉较长节点的前面多余部分,此时相同长度,之后逐个遍历是否相同即可。
python
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
if pHead1== None or pHead2 == None:
return None
pa = pHead1
pb = pHead2
while(pa!=pb):
pa = pHead2 if pa is None else pa.next
pb = pHead1 if pb is None else pb.next
return pa
c++
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
if((pHead1==NULL)||(pHead2==NULL))return NULL;
int len1=getlen(pHead1);
int len2=getlen(pHead2);
if(len1>len2){
for(int i=0;i<len1-len2;i++)pHead1=pHead1->next;
}
else{
for(int i=0;i<len2-len1;i++)pHead2=pHead2->next;}
while(pHead1!=pHead2){
pHead1=pHead1->next;
pHead2=pHead2->next;
}
return pHead1;
}
int getlen(ListNode* pHead){
int len=1;
while(pHead->next){
len++;
pHead=pHead->next;
}
return len;
}
};
32.第一个只出现一次的字符
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
思路:记录出现次数,明显要用到hash,python中使用字典dict,c++中使用STL中的map。将出现的字符放入队列,最后pop第一个只出现的一次的字符。另外,通过本题熟悉对dict和map的使用。
python
# -*- coding:utf-8 -*-
class Solution:
def FirstNotRepeatingChar(self, s):
# write code here
queue = []
memories = dict()
for idx,char in enumerate(s):
if char not in memories:
queue.append(idx)
memories[char]=0
memories[char]+=1
while(queue and memories[s[queue[0]]]>1):
queue.pop(0)
return queue[0] if queue else -1
c++
class Solution {
public:
int FirstNotRepeatingChar(string str) {
map<char, int> mp;
for(int i = 0; i < str.size(); ++i)
mp[str[i]]++;
for(int i = 0; i < str.size(); ++i){
if(mp[str[i]]==1)
return i;
}
return -1;
}
};
33.数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007。(size<=2*10^5)
思路:逆序对若是逐一对比,则复杂度为O(n2)。因此,考虑使用归并排序。每次归并时,放入右堆元素时左堆剩余元素数即此时逆序对数。
python
# -*- coding:utf-8 -*-
class Solution:
def InversePairs(self, data):
# write code here
if not data:
return 0
temp = [i for i in data]
return self.mergeSort(temp, data, 0, len(data)-1) % 1000000007
def mergeSort(self, temp, data, low, high):
if low >= high:
temp[low] = data[low]
return 0
mid = (low + high) / 2
left = self.mergeSort(data, temp, low, mid)
right = self.mergeSort(data, temp, mid+1, high)
count = 0
i = low
j = mid+1
index = low
while i <= mid and j <= high:
if data[i] <= data[j]:
temp[index] = data[i]
i += 1
else:
temp[index] = data[j]
count += mid-i+1
j += 1
index += 1
while i <= mid:
temp[index] = data[i]
i += 1
index += 1
while j <= high:
temp[index] = data[j]
j += 1
index += 1
return count + left + right
C++
class Solution {
long long count=0;
public:
int InversePairs(vector<int> data) {
if (data.size()<=1)return 0;
MergeSort(data,0,data.size()-1);
return count%1000000007;
}
void merge(vector<int>& nums, int l1, int r1, int l2, int r2 ) {
int i = l1;int j = l2;
int n = (r1 - l1 + 1) + (r2 - l2 + 1);
vector<int> temp(n);
int k = 0;
while(i<=r1&&j<=r2){
if(nums[i] < nums[j])
temp[k++] = nums[i++];
else{
temp[k++] = nums[j++];
count+=r1-i+1;}
}
while(i<=r1)
temp[k++] = nums[i++];
while(j<=r2)
temp[k++] = nums[j++];
for(int i = 0; i < n;i++)
nums[l1 + i] = temp[i];
}
void MergeSort(vector<int>& nums,int start, int end) {
if (start < end) {
int mid = (start + end) >> 1;
MergeSort(nums, start, mid);
MergeSort(nums, mid + 1, end);
merge(nums, start, mid, mid + 1, end);
}
}
};
34.最大连续子数列
计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路:若暴力遍历,则需要O(n2)。可以考虑用分治法,以递归地方式将数列分为两部分,则最大连续子数列必存在于这两部分或者两部分都有这三种情况。或者使用动态规划,找到递推公式。应当注意,若全是负数,则最大子数列之和不是0。
python
# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
LocalSum=0
Sum=0
minSum=array[0]
for i in range(len(array)):
LocalSum += array[i]
if(array[i]>minSum):
minSum=array[i]
if(LocalSum>Sum):
Sum=LocalSum
elif(LocalSum<0):
LocalSum=0
if minSum<0:
Sum=minSum
return Sum
c++
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int LocalSum=0,Sum=0,minSum=array[0];
for (int i=0;i<array.size();i++){
LocalSum+=array[i];
if(array[i]>minSum)minSum=array[i];
if(LocalSum>Sum)Sum=LocalSum;
else if(LocalSum<0)LocalSum=0;
}
if(minSum<0)Sum=minSum;
return Sum;
}
};
另外,此题有一更好的解法
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int cursum=array[0];
int maxsum=array[0];
for(int i=1;i<array.size();i++){
cursum+=array[i];
if(cursum<array[i])
cursum=array[i];
if(cursum>maxsum)
maxsum=cursum;
}
return maxsum;
}
};
35.最小的k个数
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路:本题旨在分析各种排序算法的原理,复杂度计算。选取最小的k个,因此不需要全部排序。堆排序时间复杂度O(nlogk),冒泡排序复杂度O(nk),快速排序O(nlogn)。
python
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
if not tinput:
return []
if k>len(tinput):
return []
tinput.sort()
return tinput[:k]
c++
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> v;
if(k>input.size())
return v;
sort(input.begin(),input.end());
for(int i=0;i<k;i++)
v.push_back(input[i]);
return v;
}
};
36.数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路:排序后,从中间位置向两边计数,直到不等于中间位置数值,看是否超过长度一半。
python
# -*- coding:utf-8 -*-
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
if not numbers:
return 0
numbers.sort()
mid=len(numbers)//2
times=1
if(mid-1>0):
for i in range(mid-1):
if numbers[mid-2-i]==numbers[mid-1]:
times+=1
else:
break
if(mid<len(numbers)):
for i in range(len(numbers)-mid):
if numbers[mid+i]==numbers[mid-1]:
times+=1
else:
break
if times>mid:
return numbers[mid-1]
else:
return 0
c++
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int length = numbers.size();
if (length == 0)
return 0;
sort(numbers.begin(), numbers.end());
int max_num = 0;
int num = 0;
int val = numbers[0];
for (int i = 0; i < length; i++) {
if (val == numbers[i]) {
num++;
}
else {
max_num = num > max_num ? num : max_num;
if (max_num > length / 2)
return val;
val = numbers[i];
num = 1;
}
}
max_num = num > max_num ? num : max_num;
if (max_num > length / 2)
return val;
else
return 0;
}
};
37.整数中1出现的次数
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路:单独分析1到n中每一位中出现1的次数。对于某一位数字k,若k等于0,则此位含1的次数为更高位数字乘当前位数;若k等于1,则此位含1的次数为更高位数字乘当前位数+低位数字+1;若k等于2~9,则此位含1的次数为(更高位数字+1)乘当前位数。
python
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code here
res=0
tmp=n
base=1
while tmp:
last=tmp%10
tmp=tmp/10
res+=tmp*base
if last==1:
res+=n%base+1
elif last>1:
res+=base
base*=10
return res
c++
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int i=1;
int count=0;
while(n/i!=0){
int high=n/(i*10);
int low=n-(n/i)*i;
int now=(n/i)%10;
if (now==0){
count+=high*i;
}
else if(now==1){
count+=high*i+low+1;
}
else{
count+=(high+1)*i;
}
i*=10;
}
return count;
}
};
38.把数组排成最小的数
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:并不是a小于b那么ab小于ba,因为3,31拼成331大于313,所以我们应该设置自己的一套比较规则,如果ab小于ba那么称为a小于b,所以我们需要做的是把整个数组按照我们的比较规则从小到大排列。然后从头到尾用字符串的形式串起来。此题要格外注意。
python
# -*- coding:utf-8 -*-
class Solution:
def PrintMinNumber(self, numbers):
# write code here
if not numbers:
return ""
lmb = lambda n1, n2:int(str(n1)+str(n2))-int(str(n2)+str(n1))
array = sorted(numbers, cmp=lmb)
return ''.join([str(i) for i in array])
c++
class Solution {
public:
string PrintMinNumber(vector<int> numbers) {
int len = numbers.size();
if(len == 0) return "";
sort(numbers.begin(), numbers.end(), cmp);
string res;
for(int i = 0; i < len; i++){
res += to_string(numbers[i]);
}
return res;
}
static bool cmp(int a, int b){
string A = to_string(a) + to_string(b);
string B = to_string(b) + to_string(a);
return A < B;
}
};
39.数组中重复的数字
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路:(1)本题可使用hash。(2)考虑到数组中数字范围固定,因此可以利用固定长度n的bool或int类型的数组,遍历原数组,每当出现一个数组a[i]则将新数组中b[a[i]]变换,到遍历到有变化的数字时即重复。(3)另外还有最高效的方法,不需要额外空间,从头遍历数组,若a[i]等于i,则i++;否则判断a[i]是否等于a[a[i]],若相等则返回True,否则互换两值,继续进行直到a[i]等于i。需要注意的是,互换a[i]和a[a[i]]时,赋值后a[i]已变,故用a[temp]表示而非a[a[i]]。
python
# -*- coding:utf-8 -*-
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
# write code here
if len(numbers)==0:
return False
for i in range(len(numbers)):
while(numbers[i]!=i):
if(numbers[numbers[i]]==numbers[i]):
duplication[0]=numbers[i]
return True
else:
temp=numbers[i]
numbers[i]=numbers[temp]
numbers[temp]=temp
return False
c++
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
if(numbers == NULL || length <= 0) {
return false;
}
for(int i = 0; i < length; i++) {
while(numbers[i] != i) {
if(numbers[i] == numbers[numbers[i]]) {
duplication[0] = numbers[i];
return true;
}
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
return false;
}
};
40.构建乘积数组
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…A[i-1]*A[i+1]…*A[n-1]。不能使用除法。
思路:本题若直接逐个计算的话,需要循环套循环,O(n2)的复杂度。若将其看作n乘n的矩阵,A和B分别为两边,则可通过对角线将矩阵分为上下三角。对于下三角而言,B[0]=1,B[1]=B[0]*A[0]……上三角同理。此时仅需O(n)的时间消耗。
python
# -*- coding:utf-8 -*-
class Solution:
def multiply(self, A):
# write code here
if not A:
return []
# 计算前面一部分
num = len(A)
B = [None] * num
B[0] = 1
for i in range(1, num):
B[i] = B[i-1] * A[i-1]
# 计算后面一部分
# 自下而上
# 保留上次的计算结果乘本轮新的数,因为只是后半部分进行累加,所以设置一个tmp,能够保留上次结果
tmp = 1
for i in range(num-2, -1, -1):
tmp *= A[i+1]
B[i] *= tmp
return B
c++
class Solution {
public:
vector<int> multiply(const vector<int>& A) {
vector<int>B(A.size());
int temp =1;
for (int i=0;i<A.size();i++){
B[i]=temp;
temp*=A[i];
}
temp=1;
for(int i=A.size()-1;i>=0;i--){
B[i]*=temp;
temp*=A[i];
}
return B;
}
};
41.二维数组中的查找
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:从左到右递增,从上到下递增,因此若从左上角开始找,每次面对向下和向右两条增大的路径,因此选择从左下角开始找,若偏大则向上走,若偏小则向右走。另一种思路是逐行使用二分查找。
# -*- coding:utf-8 -*-
class Solution:
# array 二维列表
def Find(self, target, array):
# write code here
rows = len(array) - 1
cols= len(array[0]) - 1
i = rows
j = 0
while j<=cols and i>=0:
if target<array[i][j]:
i -= 1
elif target>array[i][j]:
j += 1
else:
return True
return False
c++
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int rows = array.size();
int cols = array[0].size();
int i=rows-1,j=0;
while(i>=0 && j<cols){
if(target<array[i][j])
i--;
else if(target>array[i][j])
j++;
else
return true;
}
return false;
}
};
42.扑克牌顺子
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…..LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
思路:要想满足顺子,首先不能够有除大小王外重复的牌。需要把大小王作为万能牌填充,因此大小王的数量应大于除大小王外其他牌最大减最小。
python
# -*- coding:utf-8 -*-
class Solution:
def IsContinuous(self, numbers):
# write code here
if not numbers:
return 0
numbers.sort()
zeros = numbers.count(0)
for i, v in enumerate(numbers[:-1]):
if v!=0:
if numbers[i+1]==v:
return False
zeros -= (numbers[i+1]-numbers[i]-1)
if zeros<0:
return False
return True
c++
class Solution {
public:
bool IsContinuous( vector<int> numbers ) {
if(numbers.size()==0)return false;
int count[14]={0};
int min=14;
int max=-1;
for(int i=0;i<numbers.size();i++){
if(numbers[i]==0)continue;
else{
if (count[numbers[i]]!=0)return false;
else count[numbers[i]]++;
if (min>numbers[i])min=numbers[i];
if (max<numbers[i])max=numbers[i];
}
}
if(max-min>=5)return false;
else return true;
}
};
43.孩子们的游戏
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
思路:此题为经典的约瑟夫环。若是无脑求解,可以用环形链表逐次删除节点。但若想递归求解,则需要分析问题,对于每次n个人报数,其点到的人的位置与剩下的n-1个人中点到的人的位置有关,因此可以写出递归式,详见博客。
python
# -*- coding:utf-8 -*-
class Solution:
def LastRemaining_Solution(self, n, m):
# write code here
if n < 1 or m < 1:
return -1
last = 0 #n=1
for i in range(2, n + 1):
last = (last + m ) % i
return last
c++
class Solution {
public:
int LastRemaining_Solution(int n, int m)
{
if(n==0) return -1;
int s=0;
for(int i=2;i<=n;i++){
s=(s+m)%i;
}
return s;
}
};
44.正则表达式匹配
请实现一个函数用来匹配包括’.’和’‘的正则表达式。模式中的字符’.’表示任意一个字符,而’‘表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”ab*ac*a”匹配,但是与”aa.a”和”ab*a”均不匹配。
思路:采用递归,分情况讨论。
python
# -*- coding:utf-8 -*-
class Solution:
# s, pattern都是字符串
def match(self, s, pattern):
# write code here
if (len(s) == 0 and len(pattern) == 0):
return True
if (len(s) > 0 and len(pattern) == 0):
return False
if (len(pattern) > 1 and pattern[1] == '*'):
if (len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.')):
return (self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern))
else:
return self.match(s, pattern[2:])
if (len(s) > 0 and (pattern[0] == '.' or pattern[0] == s[0])):
return self.match(s[1:], pattern[1:])
return False
c++
class Solution {
public:
bool match(char* str, char* pattern)
{
if (pattern[0] == 0 && str[0] == 0){
return true;
}
if (pattern[0] != 0 && pattern[1] == '*'){
if (match(str, pattern + 2))
return true;
}
if ((pattern[0] == '.' && str[0]) || str[0] == pattern[0]){
if (match(str + 1, pattern + 1))
return true;
if (pattern[1] == '*' && match(str + 1, pattern)){
return true;
}
}
return false;
}
};
45.表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。
思路:按照至多只有一个e或E,e前后各至多只能一个正负符号,e后无小数点,后面的正负号紧跟e后面等。本题关键是理清逻辑。另外,注意else if与多个if的区别,else if只要满足一个,后面的else if便不再判断。
python
# -*- coding:utf-8 -*-
class Solution:
# s字符串
def isNumeric(self, s):
# write code here
hasE=False;sign=False;decimal=False;
for i in range(len(s)):
if s[i]=='e' or s[i]== 'E':
if i==len(s)-1:
return False
if hasE:
return False
hasE=True
elif s[i]=='+' or s[i]=='-':
if sign and s[i-1]!='e' and s[i-1]!='E':
return False
if (not sign) and i>0 and s[i-1]!='e' and s[i-1]!='E':
return False
sign = True
elif s[i]=='.':
if decimal or hasE:
return False
decimal = True
elif s[i]<'0' or s[i]>'9':
return False
return True
c++
class Solution {
public:
bool isNumeric(char* str) {
bool sign = false, decimal = false, hasE = false;
for (int i = 0; i < strlen(str); i++) {
if (str[i] == 'e' || str[i] == 'E') {
if (i == strlen(str)-1) return false;
if (hasE) return false;
hasE = true;
}
else if (str[i] == '+' || str[i] == '-') {
if (sign && str[i-1] != 'e' && str[i-1] != 'E') return false;
if (!sign && i > 0 && str[i-1] != 'e' && str[i-1] != 'E') return false;
sign = true;
}
else if (str[i] == '.') {
if (hasE || decimal) return false;
decimal = true;
}
else if (str[i] < '0' || str[i] > '9')
return false;
}
return true;
}
};
46.字符流中第一个不重复的字符
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。如果当前字符流没有存在出现一次的字符,返回#字符。
思路:使用队列和hash,即c++中的map和python中的dict,注意语法。另外,c++的queue中,push而非push_back,pop并没有返回值,需要用a.front()。
python
# -*- coding:utf-8 -*-
class Solution:
# 返回对应char
def __init__(self):
self.letter=dict()
self.queue=[]
def FirstAppearingOnce(self):
# write code here
while len(self.queue) and self.letter[self.queue[0]]>1:
self.queue.pop(0)
return self.queue[0] if len(self.queue) else '#'
def Insert(self, char):
# write code here
if char not in self.letter:
self.letter[char]=0
self.letter[char]+=1
if self.letter[char]==1:
self.queue.append(char)
c++
class Solution
{
map<char,int>letter;
queue<char>myqueue;
public:
//Insert one char from stringstream
void Insert(char ch)
{
letter[ch]++;
if (letter[ch]==1){
myqueue.push(ch);
}
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
while((myqueue.size()!=0)&&(letter[myqueue.front()]!=1)){
myqueue.pop();}
if(myqueue.size()!=0)return myqueue.front();
return'#';
}
};
47.替换空格
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路:注意在c++中,空格本身占一个char的位置,替换成”%20”后占三个char,因此指针需要延后。所以选择将变换后的内容保存在新的vector中,完全处理后再拷贝至原首位置。
python
# -*- coding:utf-8 -*-
class Solution:
# s 源字符串
def __init__(self):
self.other=[]
def replaceSpace(self, s):
# write code here
for lett in s:
if lett==' ':
self.other+="%20"
else:
self.other.append(lett)
return ''.join(self.other)
c++
class Solution {
vector<char>other;
int count=0;
public:
void replaceSpace(char *str,int length) {
char *str1=str;
for (int i=0;i<length;i++){
if (*str==' ') {
other.push_back('%');
other.push_back('2');
other.push_back('0');
count+=3;
}
else{
other.push_back(*str);
count+=1;
}
str++;
}
for(int j=0;j<count;j++){
*str1=other[j];
str1++;
}
}
};
48.矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串”bcced”的路径,但是矩阵中不包含”abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
思路:采用深度优先搜索,递归进行。
python
# -*- coding:utf-8 -*-
class Solution:
def hasPath(self, matrix, rows, cols, path):
# write code here
for i in range(rows):
for j in range(cols):
if matrix[i*cols+j] == path[0]:
if self.find(list(matrix),rows,cols,path[1:],i,j):
return True
return False
def find(self,matrix,rows,cols,path,i,j):
if not path:
return True
matrix[i*cols+j]='0'
if j+1<cols and matrix[i*cols+j+1]==path[0]:
return self.find(matrix,rows,cols,path[1:],i,j+1)
elif j-1>=0 and matrix[i*cols+j-1]==path[0]:
return self.find(matrix,rows,cols,path[1:],i,j-1)
elif i+1<rows and matrix[(i+1)*cols+j]==path[0]:
return self.find(matrix,rows,cols,path[1:],i+1,j)
elif i-1>=0 and matrix[(i-1)*cols+j]==path[0]:
return self.find(matrix,rows,cols,path[1:],i-1,j)
else:
return False
49.机器人的运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路:同样是DFS。
python
# -*- coding:utf-8 -*-
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
board = [[0 for _ in range(cols)] for _ in range(rows)]
def block(r,c):
s = sum(map(int,str(r)+str(c)))
return s>threshold
class Context:
acc = 0
def traverse(r,c):
if not (0<=r<rows and 0<=c<cols): return
if board[r][c]!=0: return
if board[r][c]==-1 or block(r,c):
board[r][c]=-1
return
board[r][c] = 1
Context.acc+=1
traverse(r+1,c)
traverse(r-1,c)
traverse(r,c+1)
traverse(r,c-1)
traverse(0,0)
return Context.acc
50.1+2+3+…+n
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
思路:不能使用一系列条件语句,则考虑其他方法终止迭代或循环。考虑短路特性,即多个条件and中,若前面出现false,则终止,不再进行后面的。
python
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.sum = 0
def Sum_Solution(self, n):
# write code here
def qiusum(n):
self.sum += n
n -= 1
return n>0 and self.Sum_Solution(n)
qiusum(n)
return self.sum
51.不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
思路:不能使用加减乘除四则运算,则考虑使用位运算。在数字电路基础中学过加法运算,当前位为两数该位异或运算,向下一位进位为当前位与运算。循环进行直到进位为0。本题用python一直超时。
c++
class Solution {
public:
int Add(int num1, int num2)
{
int re1=num1^num2;
int re2=num1&num2;
while(re2){
int temp1=re1;
int temp2=re2<<1;
re1=temp1^temp2;
re2=temp1&temp2;
}
return re1;
}
};
52.二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:二叉搜索树按照中序遍历即有序数组,因此递归进行处理,将左子树的最右端节点的right指向root,root的left指向左子树最右端节点,右子树同理。注意判断是否为NULL即可。
c++
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree==NULL)
return NULL;
if(pRootOfTree->left==NULL&&pRootOfTree->right==NULL)
return pRootOfTree;
TreeNode* left = Convert(pRootOfTree->left);
TreeNode* curr = left;
while(curr!=NULL&&curr->right!=NULL)
curr=curr->right;
if(curr!=NULL)
{
curr->right=pRootOfTree;
pRootOfTree->left = curr;
}
TreeNode* right = Convert(pRootOfTree->right);
if(right!=NULL)
{
pRootOfTree->right = right;
right->left = pRootOfTree;
}
return left!=NULL?left:pRootOfTree;
}
};