不使用加号的加法
LeetCode 371
输入:a=1,b=2
输出:3
/* 思路:不使用加号的加法一般有三步:1)计算a^b,这个计算出来的是不考虑进位的值;2)a&b这个计算出来的是考虑进位的值;3)将考虑进位的值向左移动1位,作为b,将不考虑进位的值作为a,递归调用此函数。 */ class Solution { public: int getSum(int a, int b) { if(b == 0) return a; int axor = a ^ b; int axand = a & b; int res = getSum(axor, axand<<1); return res; } };
不用除号的除法
LeetCode 29
输入:dividend = 10, divisor = 3
输出:3
输入:dividend = 7, divisor = -3
输出:-2
/* 思路:题目要求不使用乘数号,其实除法相当于给被除数减除数,直到被除数小于等于0。因此,我们可以先对除数进行乘2操作,找到最小的大于被除数的值,这时进行了几次操作乘2操作,就是商的值,最后再对符号进行处理即可。 */ class Solution { public: int divide(int dividend, int divisor) { int sign = (dividend < 0) ^ (divisor < 0) ? -1 : 1; long long int m = abs((long long) dividend); long long int n = abs((long long) divisor); long long res = 0; while(m >= n) { long long temp = n; long long i = 1; while(temp << 1 < m) { temp = temp<<1; i = i<<1; } m -= temp; res += i; } if(sign < 0) res = -res; return res > INT_MAX ? INT_MAX: res; } };
计算数组中其余元素乘积
LeetCode 238
给定一个数组,输出另外一个数组,输出数组每一位代表输入数组除了这一位以外,其余位的乘积。
输入:[1,2,3,4]
输出:[24,12,8,6]
class Solution { public: vector<int> productExceptSelf(vector<int>& nums) { int len = nums.size(); vector<int> fromBegin(len); vector<int> fromLast(len); vector<int> res(len); fromBegin[0] = 1; fromLast[0] = 1; for(int i = 1; i < len; ++i) { fromBegin[i] =fromBegin[i-1] * nums[i - 1]; fromLast[i] = fromLast[i-1] * nums[len - i]; } for(int i = 0; i < len; ++i) res[i] = fromBegin[i] * fromLast[len - i - 1]; return res; } };
最大二叉树深度
LeetCode 104
最大二叉树深度实际上就是二叉树的深度。
输入:[3,9,20,null,null,15,7]
3 / \ 9 20 / \ 15 7
输出:3
方法一:递归法
/* 思路:采用递归的思路,进行层序遍历,即可求出最大深度。 */ /** * Definition for binary tree * 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 ldepth = maxDepth(root->left) + 1; int rdepth = maxDepth(root->right) + 1; return max(ldepth,rdepth); } };
方法二:引入queue
/* 思路:常用的层序遍历方法是采用队列,将每一层元素依次入队列,然后进行深度的计算 */ /** * 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 == nullptr) return 0; int left = maxDepth(root->left) + 1; int right = maxDepth(root->right) + 1; return max(left,right); }*/ int maxDepth(TreeNode* root) { if(root == nullptr) return 0; queue<TreeNode*> q; int count = 0; int next = 1; q.push(root); int depth = 0; while(q.size() != 0) { TreeNode* current = q.front(); q.pop(); count++; if(current->left != NULL) q.push(current->left); if(current->right != NULL) q.push(current->right); if(count == next) { count = 0; depth++; next = q.size(); } } return depth; } };
最小二叉树深度
LeetCode 111
因为深度是必须到叶子节点的距离,因此使用深度遍历时,不能单纯的比较左右子树的递归结果返回较小值,因为对于有单个孩子为空的节点,为空的孩子会返回0,但是这个节点并非叶子节点,所以返回结果是错误的。因此,当发现当前处理的节点有单个孩子是空时,返回一个极大值INT_MAX,防止其干扰结果。
/** * 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 minDepth(TreeNode* root) { if(root == nullptr) return 0; if(!root->left && !root->right) return 1; int leftDepth = 1 + minDepth(root -> left); leftDepth = ((leftDepth == 1)? INT_MAX : leftDepth); int rightDepth = 1 + minDepth(root -> right); rightDepth = ((rightDepth == 1) ? INT_MAX : rightDepth); return min(leftDepth, rightDepth); } };
镜像二叉树
(1) 剑指offer
给定一个二叉树,将其变换为原二叉树的镜像
二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ 11 9 7 5
/* 思路:将二叉树转换为镜像二叉树,可以使用递归的方法。如果输入节点为空,则返回;如果输入节点的左右子树都为空,则返回;否则将左右子树交换。如果左子树非空,则递归调用左子树;若右子树非空,则递归调用右子树。 */ 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 == NULL) return; if(pRoot->left == NULL && pRoot->right == NULL) return; swap(pRoot->left,pRoot->right); if(pRoot->left!=NULL) Mirror(pRoot->left); if(pRoot->right!=NULL) Mirror(pRoot->right); } };
(2) LeetCode 101
给定一个二叉树,判断它是否是镜像的。
例如,下面这个二叉树就是镜像的
1 / \ 2 2 / \ / \ 3 4 4 3
下面这个二叉树就是非镜像的
1 / \ 2 2 \ \ 3 3
/* 思路:函数输入的是一个根节点,将如果根节点为空,则返回true;否则将根节点作为两个节点传入Mirror函数来判断。要是两个根节点都是空,则返回true,要是其中一个为空,则返回false;若两个节点的值不同,则返回false;否则,将第一个节点的左子树和第二个节点的右子树带入Mirror函数,同时将第一个节点的右子树和第二个节点的左子树带入Mirror函数,取两者的与。 */ /** * 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; return MirrorTree(root,root); } bool MirrorTree(TreeNode* root1, TreeNode* root2) { if(!root1&&!root2) return true; if(!root1||!root2) return false; if(root1->val != root2->val) return false; return MirrorTree(root1->left,root2->right)&&MirrorTree(root1->right,root2->left); } };
不使用乘除法和控制语句的n个数求和
剑指offer
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
/* 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 思路: 利用&&短路原理,并使用递归,可以实现求和的过程 */ class Solution { public: int Sum_Solution(int n) { int temp = n; temp && (temp+=Sum_Solution(temp-1)); return temp; } };
反转链表
LeetCode 206
反转单链表
输入:1->2->3->4->5->NULL
输出:5->4->3->2->1->NULL
/* 思路:使用三个指针,一个指针用于存储当前节点,一个指针存储前一个节点,一个指针存储下一个节点。只要当前节点不为空,就将下一个节点当前节点的下一个节点存在临时变量中,然后将下一个节点更新为前一个节点,将前一个节点更新为当前节点,将当前节点更新为下一个节点。 */ /** * 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) { ListNode *cur = head; ListNode *pre = NULL; while(cur != NULL) { ListNode *temp = cur->next; cur->next = pre; pre = cur; cur = temp; } return pre; } };
质数判断
判断质数常用的一种方法,就是从2开始,到sqrt(n)结束,如果都不能整除n,则此数为质数。
class Solution{ public: bool isPrime(int n) { for(int i = 2; i < sqrt(n); ++i) { if(n % i == 0) return false; } return true; } };
最大公约数
求最大公约数有两种方法:
方法一:辗转相除
/* 思路:给定两个数a和b,使得a为较大的数,b为较小的数。如果a%b为0的话,b就是最大公约数;如果不为0,则将a更新为b,将b更新为a%b即可。 */ int gcd(int a, int b) { //首先进行a和b顺序确定 if(a < b) { a = a + b; b = a - b; a = a - b; } c = a % b; while(a % b != 0) { a = b; b = c; c = a % b; } return b; }
方法二:循环遍历
/* 思路:给定a、b两个数,将较小的数赋值给c,c = b(a > b),将a和b对c做求余操作,从c开始一次向下遍历,直到两者的余数都为0,否则c减1,继续循环遍历。 */ int gcd(int a, int b) { int c; c = (a > b) ? b : a; while(a % c != 0 || b % c != 0) { c-- } return c; }
最小公倍数
最小公倍数可以依靠最大公约数来求解,设c为a和b的最大公约数,则最小公倍数为a * b / c
int LeastCommonMultiple(int a, int b) { return a * b / gcd(a , b); }
水仙花数
遍历输入的数字,将数字存储啊在vector中,获得vector的长度即为指数,然后加和所有数字的长度次方与输入数对比即可。
#include<iostream> #include<string> #include<vector> #include<math.h> using namespace std; bool isLegalNumber(int n); int main() { int num; while(cin>>num) { if(isLegalNumber(num)) cout<<"true"<<endl; else cout<<"false"<<endl; } } bool isLegalNumber(int n) { int temp = n; vector<int> number; while(temp != 0) { number.push_back(temp % 10); temp = temp / 10; } int len = number.size(); int ans = 0; for(int i = len - 1; i >= 0; --i) { int t = pow(number[i], len); ans = ans + t; } if(ans == n) return true; else return false; }
丑数
LeetCode 263
输入一个数,判断这个是否为丑数。丑数即因子只有2、3和5的数。
/* 思路:首先对边界数0进行操作,当输入为0时,输出false; 然后对输入进行除2操作,直到不能被2整除,然后对其进行除3操作,直到不能整除,然后对其进行除5操作,直到不能整除。最后判断商是否为1,若为1则返回true,否则返回false。 */ class Solution { public: bool isUgly(int num) { if(num == 0) return false; while(num % 2 == 0) num /= 2; while(num % 3 == 0) num /= 3; while(num % 5 == 0) num /= 5; if(num == 1) return true; else return false; } };
LeetCode 264
输入一个数n,返回第n个丑数。
/* 思路:定义变量i,j,k分别表示2的因子的数,3的因子的数和5的因子的数,每次选择其中最小的数加入容器,最后返回容器顶部的数。 */ class Solution { public: int nthUglyNumber(int n) { int i = 0, j = 0, k = 0; vector<int> res(1,1); while(res.size() < n) { res.push_back(min(2 * res[i] , min(3 * res[j], 5 * res[k]))); if(res.back() == res[i] * 2) i++; if(res.back() == res[j] * 3) j++; if(res.back() == res[k] * 5) k++; } return res.back(); } };