21.给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1 和 0。
示例 1:
输入: a = "11", b = "1" 输出: "100"
示例 2:
输入: a = "1010", b = "1011" 输出: "10101"
class Solution {
public:
string addBinary(string a, string b) {
int la = a.size();
int lb = b.size();
if(la < lb){
swap(a, b);
swap(la, lb);
}
if(la - lb > 0)
b.insert(0, la - lb, '0');
int pre = 0, cur = 0;
string res;
for(int i = la - 1; i >= 0; i--){
int ia = a[i] - '0';
int ib = b[i] - '0';
cur = ia ^ ib ^ pre; // 二进制数相加结果与异或结果相同
if(ia + ib + pre >= 2) pre = 1;
else pre = 0;
res.insert(0, 1, cur + '0');
}
if(pre) // 最高位的进位单独处理
res.insert(0, 1, pre + '0');
return res;
}
};
22.实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4 输出: 2
示例 2:
输入: 8 输出: 2 说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
class Solution {
public:
int mySqrt(int x) {
// 牛顿法
// f(x) = x^2 - a
// 求解 a 的平方根, 即求解 f(x) = 0 的解
// f(x) ~= f(x0) + f'(x0)*(x - x0) ;
// 令 f(x)=0 => x=(x0 +a/x0)/2
long res=x;
while(res*res>x)
res=(res+x/res)/2;
return (int)res;
}
};
23.假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2 输出: 2 解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3 输出: 3 解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
class Solution {
public:
int climbStairs(int n) {
if(n<=3)
return n;
long t;
long a=1,b=2;
for(int i=1;i<n;i++)
{
t=a+b;
a=b;
b=t;
}
return a;
}
};
24.给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
//我自己的菜逼解法
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
vector<int> res(m+n);
int i=0,j=0,k=0;
for(;i<m&&j<n;k++)
res[k]=nums1[i]<=nums2[j]?nums1[i++]:nums2[j++];
while(i<m)
res[k++]=nums1[i++];
while(j<n)
res[k++]=nums2[j++];
nums1=res;
}
};
//参考大佬答案后的高级解法
//从后往前数则不需要考虑nums1比较剩余下来的一些数
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int p=m-- + n-- -1;
while(m>=0&&n>=0)
nums1[p--]=nums1[m]>nums2[n]:nums1[m--]:nums2[n--];
while(n>=0)
nums1[p--]=nums2[n--];
}
};
25.给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1
/ \ /
2 3 2 3
[1,2,3], [1,2,3]
输出: true
示例 2:
输入: 1 1
/
2 2
[1,2], [1,null,2]
输出: false
示例 3:
输入: 1 1
/ \ /
2 1 1 2
[1,2,1], [1,1,2]
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(!(p&&q)&&(p||q))
return false;
if(!(p||q))
return true;
return (p->val==q->val)&&(isSameTree(p->left,q->left))&&(isSameTree(p->right,q->right));
}
};
26.给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [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
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(!root)
return true;
return isMirror(root->left,root->right);
}
bool isMirror(TreeNode* p, TreeNode* q) {
if(!(p&&q)&&(p||q))
return false;
if(!(p||q))
return true;
return (p->val==q->val)&&(isMirror(p->left,q->right))&&(isMirror(p->right,q->left));
}
};
27.给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例: 给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
class Solution {
public:
int maxDepth(TreeNode* root) {
if(!root)
return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
28.将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9 / / -10 5
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
cout<<endl;
TreeNode *res=new TreeNode(0);
if(nums.size()<1)
return NULL;
int n=nums.size();
vector<int> nums1(n/2),nums2(n-n/2-1);
for(int i=0;i<n/2;i++)
nums1[i]=(nums[i]);
for(int i=nums.size()/2+1,j=0;i<n;i++)
nums2[j++]=(nums[i]);
res->val=nums[n/2];
res->left=sortedArrayToBST(nums1);
res->right=sortedArrayToBST(nums2);
return res;
}
};
29.给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/
9 20
/
15 7
返回 true 。
class Solution {
public:
int flag=0;
bool isBalanced(TreeNode* root) {
return high(root)+1;
}
int high(TreeNode* root)
{
if(root==NULL)
return 0;
int lhigh=high(root->left);
int rhigh=high(root->right);
if(abs(lhigh-rhigh)>1||lhigh==-1||rhigh==-1)
return -1;
return max(lhigh,rhigh)+1;
}
};
30.给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最小深度 2.
class Solution {
public:
int minDepth(TreeNode* root) {
if(!root)
return 0;
int left=minDepth(root->left),right=minDepth(root->right);
return (left && right) ? 1+min(left,right):1+left+right;
}
};
31.给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例: 给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
class Solution {
public:
bool hasPathSum(TreeNode* root, int sum) {
if (root==NULL)
return false;
if (root->left==NULL&&root->right==NULL)
return sum-root->val==0;
return hasPathSum(root->left,sum-root->val)||hasPathSum(root->right,sum-root->val);
}
};
32.给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int k=0;
int max=0;
for(int i=0;i<prices.size();i++)
{
if(prices[i]-prices[k]>max)
max=prices[i]-prices[k];
if(prices[k]>prices[i])
k=i;
}
return max;
}
};
33.给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4] 输出: 7
class Solution {
public:
int maxProfit(vector<int>& prices) {
int sum=0;
for(int i=1;i<prices.size();i++)
sum+=max(0,prices[i]-prices[i-1]);
return sum;
}
};
34.给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res=0;
for(int i=0;i<nums.size();i++)
res^=nums[i];
return res;
}
};
35.给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *p=head;
while(p&&p->next)
{
head=head->next;
p=p->next->next;
if(p==head)
return true;
}
return false;
}
};
36.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:tail connects to node index 1 解释:链表中有一个环,其尾部连接到第二个节点。
/*假设p为慢指针,q为快指针
设从头到环的长度为a,环的长度为b
则
p=a+x(x为在环里面走的长度)
q=a+x+mb=2a+2x(m为正整数)
:mb=a+x
q+a=2a+x+mb=a+2mb
所以只要将p在设为head,p和q每次走一步,再次相遇就是环的初始节点*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *p=head,*q=head;
while(q&&q->next)
{
p=p->next;
q=q->next->next;
if(q==p)
{
p=head;
while(p!=q)
{
p=p->next;
q=q->next;
}
return p;
}
}
return NULL;
}
};
37.编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 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 个节点。
解法1:计算两个链表的长度相减,然后更长的那个来走一段路长,再用双指针判断
解法2:map映射
解法3:使用两个栈
解法4:将某个链表结尾指向头部,使得形成环,再用上题的方式来解决
下面贴出解法2的代码:
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
map<ListNode*, bool> vis;
while(headA != NULL){
vis[headA] = true;
headA = headA->next;
}
while(headB!=NULL){
if(vis[headB]) return headB;
vis[headB] = true;
headB = headB->next;
}
return NULL;
}
};
38.给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
//考虑子问题,若总和太大则一定是后面的太大,因为无路可走了,所以排除后面一个后更新整个结构,不再考虑后面的
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int l=0,r=numbers.size()-1;
int ret[2];
while (l<r){
if (numbers[l]+numbers[r]==target){
ret[0]=l+1;
ret[1]=r+1;
break;
} else if(numbers[l]+numbers[r]<target)
l++;
else
r--;
}
return vector<int>(ret,ret+2);
}
};
39.给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。
示例 1:
输入: [3,2,3] 输出: 3
示例 2:
输入: [2,2,1,1,1,2,2] 输出: 2
//这题的主要重点是众数的数量大于n/2,即即使减去所有的不相同的数的数量留存的依旧是众数
class Solution {
public:
int majorityElement(vector<int>& nums) {
int k=0;
int res=0;
for(int i=0;i<nums.size();i++)
{
if(!k)
{
res=i;
k=1;
}
else
{
if(nums[res]==nums[i])
k++;
else
k--;
}
}
return nums[res];
}
};
40.给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 1:
输入: 3 输出: 0 解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5 输出: 1 解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
//2*5=10,2的数量一定比5的多,问题转换为求所有的乘法因子中所有5的数量
class Solution {
public:
int trailingZeroes(int n) {
int count=0;
while(n>=5)
{
count+=n/5;
n=n/5;
}
return count;
}
};