修改于2022.1.1
写在前面:
转载请注明本文链接:https://www.cnblogs.com/jxingh/p/15598210.html
820算法题
数组
1、数组逆置问题(左移、右移)
void reverse(int a[],int left, int right){
int temp;
for(int i=left,j=right; i<j; ++i,--j){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
2、数组中超过一半的数字
// 默认都是正整数,存在则返回c,不存在则返回-1
int majorityElement(vector<int>& nums) {
int n = nums.size();
int c = nums[0];
int num = 1;
for(int i=1; i<n; i++){
if(num == 0) c = nums[i];
if(nums[i] == c) ++num;
else --num;
}
num = 0;
for(int i=0; i<n; i++){
if(nums[i] == c) num++;
}
if(num > n/2) return c;
else return -1;
}
3、荷兰国旗问题
void sortColor(int nums[], int length){
int i=0, j=0, k=length-1;
while(j<=k){
if(nums[j]<0){
Swap(nums+i, nums+j);
i++;
j++;
}
else if(nums[j]==0){
j++;
}
else{
Swap(nums+j, nums+k);
k--;
}
}
}
4、股票最佳卖出时机
int maxProfit(vector<int>& prices) {
if(prices.size() < 2) return 0;
int res = 0, min = prices[0];
for(int i = 1; i < prices.size(); i++) {
if(prices[i] <= min) {
min = prices[i];
}else {
res = res > (prices[i] - min) ? res : (prices[i] - min);
}
}
return res;
}
int getMax(int* array, int n) {
int res = INT_MIN, max = array[0];
for(int i = 1; i < n; i++) {
if(array[i] >= max) {
max = array[i];
}else {
res = res > (max - array[i]) ? res : (max - array[i]);
}
}
return res;
}
链表
struct ListNode{
int val;
ListNode *next;
};
1、反转链表
ListNode* reverseList(ListNode* head) {
ListNode* p = head;
head = NULL;
while(p){
ListNode* q = p;
p = p->next;
q->next = head;
head = q;
}
return head;
}
// 头结点不含信息
2、合并两升序链表
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *head = (ListNode*) malloc(sizeof(ListNode));
ListNode* p = head;
while(l1 && l2){
if(l1->val < l2->val){
p->next = l1;
l1 = l1->next;
}
else {
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
if(l1 == NULL) p->next =l2;
else p->next = l1;
return head->next;
}
3、反向打印链表
vector<int> reversePrint(ListNode* head) {
if(!head) return {};
vector<int> vec;
stack<int> st;
while(head){
st.push(head->val);
head = head->next;
}
while(!st.empty()){
vec.push_back(st.top());
st.pop();
}
return vec;
}
// printf(head->next);
4、寻找相交链表的公共结点
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(!headA || !headB) return NULL;
ListNode* p=headA;
ListNode* q=headB;
int lenA=0;
int lenB=0;
while(p){
lenA++;
p=p->next;
}
while(q){
lenB++;
q=q->next;
}
p=headA;
q=headB;
if(lenA>lenB){
int len=lenA-lenB;
while(len){
p=p->next;
len--;
}
}
else{
int len=lenB-lenA;
while(len){
q=q->next;
len--;
}
}
while(p){
if(p==q) return p;
p=p->next;
q=q->next;
}
return NULL;
}
5、倒数第k个结点
ListNode* getKthFromEnd(ListNode* head, int k) {
if(head==NULL || k<1) return NULL;
ListNode* fast=head;
ListNode* slow=head;
while(k > 0){
if(fast == NULL) return NULL;
fast = fast->next;
k--;
}
while(fast!=NULL){
fast = fast->next;
slow = slow->next;
}
return slow;
}
6、判断链表是否有环
bool hasCycle(ListNode *head) {
if(head == NULL || head->next == NULL) return false;
ListNode* fast=head;
ListNode* slow=head;
while(fast != NULL && fast->next != NULL){
slow=slow->next;
fast=fast->next->next;
if(fast == slow) return true;
}
return false;
}
7、寻找链表中点(有两个中间结点,则返回第二/一个中间结点)
ListNode* middleNode(ListNode* head) {
if(head == NULL || head->next == NULL) return head;
ListNode *slow = head;
ListNode *fast = head;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
8、删除链表的倒数第 N 个结点(思考)
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *fast = head;
ListNode *slow = head;
for(int i=0; i<n; i++) {
fast = fast->next;
}
ListNode *p = NULL;
if(fast==NULL){
p = head;
head = p->next;
delete p;
return head;
}
while(fast->next) {
fast = fast->next;
slow = slow->next;
}
p = slow->next;
slow->next = p->next;
delete p;
return head;
}
栈和队列(简答题)
1、双队列实现栈(2018)
2、双栈实现队列
3、循环链表实现队列(2021)
// q入队
ListNode *p = rear->next;
rear->next = q;
q->next = p;
rear = q;
// 出队
rear->next = rear->next->next;
二叉树
struct TreeNode{
int val;
TreeNode *left, *right;
};
1、前中后序遍历
void preOrder(TreeNode* root){
if(root!=NULL){
visit(root);
preOrder(root->left);
preOrder(root->right);
}
}
void inOrder(TreeNode* root){
if(root!=NULL){
inOrder(root->left);
visit(root);
inOrder(root->right);
}
}
void postOrder(TreeNode* root){
if(root!=NULL){
postOrder(root->left);
postOrder(root->right);
visit(root);
}
}
2、层次遍历
//按层输出
vector<vector<int>> levelOrder(TreeNode* root) {
//if(root == NULL) return {};
vector<vector<int>> res;
queue<TreeNode*> Q;
if(root) Q.push(root);
while(!Q.empty()){
int len = Q.size(); //记录当前层的节点数
vector<int> vec;
for(int i=0; i<len; ++i){
TreeNode *p = Q.front();
q.pop();
vec.push_back(p->val);
if(p->left != NULL) Q.push(p->left);
if(p->right != NULL) Q.push(p->right);
}
res.push_back(vec);
}
return res;
}
3、二叉树高度
int height(TreeNode* root){
if (root == NULL) return 0;
int L = height(root->left);
int R = height(root->right);
return (L > R ? L : R) + 1;
}
4、判断对称二叉树(镜像)(2021)
// 一个树的左子树与右子树镜像对称,那么这个树是对称的
//两个树互为镜像:
// 它们的两个根结点具有相同的值
// 每个树的右子树都与另一个树的左子树镜像对称
bool isSymmetric(TreeNode* root) {
if(root==NULL) return true;
return check(root->left, root->right);
}
bool check(TreeNode *p, TreeNode *q) {
//递归的终止条件是两个节点都为空
//或者两个节点中有一个为空
//或者两个节点的值不相等
if (p==NULL && q==NULL) return true;
else if (p==NULL || q==NULL) return false;
return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
}
5、判断平衡二叉树
bool isBalanced(TreeNode* root) {
if (root == NULL) return true;
else {
return abs(height(root->left) - height(root->right)) <= 1 &&
isBalanced(root->left) && isBalanced(root->right);
}
}
int height(TreeNode* root){
if (root == NULL) return 0;
int L = height(root->left);
int R = height(root->right);
return (L > R ? L : R) + 1;
}
// 时间复杂度:O(n^2),空间复杂度:O(n)
// 思考:时间复杂度怎么降到 O(n)?
bool isBalanced(TreeNode* root) {
return height(root)>=0;
}
int height(TreeNode* root) {
if(root == NULL) return 0;
int L = height(root->left);
int R = height(root->right);
if(L == -1 || R == -1 || abs(L - R) > 1)
return -1;
/** 左子树已经返回-1了就不需要再递归右子树
* int L, R;
* if((L = height(root->left)) == -1 || (R = height(root->right)) == -1 || abs(L - R) > 1)
* return -1;
*/
return (L > R ? L : R) + 1;
}
6、判断完全二叉树(王道141)
bool isCompleteTree(TreeNode* root) {
if(root == NULL) return true;
queue<TreeNode*> Q;
Q.push(root);
while(!Q.empty()) {
TreeNode *p = Q.front();
Q.pop();
if(p!=NULL) {
Q.push(p->left);
Q.push(p->right);
}
else {
while(!Q.empty()) {
TreeNode *p = Q.front();
Q.pop();
if(p!=NULL) return false;
}
}
}
return true;
}
7、判断二叉搜索树
vector<int> res;
bool isValidBST(TreeNode* root) {
if(!root) return true;
inOrder(root);
for(int i=1; i<res.size(); ++i){
if(res[i] <= res[i-1]) return false;
}
return true;
}
void inOrder(TreeNode* root) {
if(root) {
inOrder(root->left);
res.push_back(root->val);
inOrder(root->right);
}
}
bool isValidBST(TreeNode* root) {
return preOrder(root, INT_MIN, INT_MAX);
}
bool preOrder(TreeNode* root, int low, int high){
if(root==NULL) return true;
if(root->val <= low || root->val >= high) return false;
return preOrder(root->left, low, root->val) && preOrder(root->right, root->val, high);
}
bool isValidBST(TreeNode *root) {
int tmp = INT_MIN;
return bst(root);
}
bool bst(TreeNode *root) {
if(root == NULL) return true;
if(bst(root->left) == false) return false;
if(root->val <= tmp) return false;
tmp = root->val;
return bst(root->right);
}
8、判断子结构(2018)
// 注:空结点不为任何树的子结构
bool isSubStructure(TreeNode *A, TreeNode *B) {
//当A或B为null时,返回false
if(A == null || B == null) return false;
//若A和B不为空,首先调用isSub方法,判断二叉树B是否为根节点与二叉树A根节点相同的子结构
//接着判断二叉树B是不是A的左子树或者右子树的子结构
return isSub(A,B) || isSubStructure(A->left,B) || isSubStructure(A->right,B);
}
// 判断二叉树B是否为根节点与二叉树A根节点相同的子结构
bool isSub(TreeNode *A,TreeNode *B){
if(B == null) return true;
if(A == null || A->val != B->val) return false;
return isSub(A->left, B->left) && isSub(A->right, B->right);
}
9、翻转二叉树
// 自底向上(后序)
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return NULL;
TreeNode* left = invertTree(root->left);
TreeNode* right = invertTree(root->right);
root->left = right;
root->right = left;
return root;
}
// 思考:尝试用先序来写?
// 后序先序都可以 中序不可以?
10、二叉树宽度
//宽度:具有结点数最多的那一层的结点个数
int getWidth(TreeNode* root) {
if(root == NULL) return 0;
int width = 1;
queue<TreeNode*> Q;
Q.push(root);
while(!Q.empty()){
int len = Q.size(); //本层宽度
for(int i=0; i<len; ++i){
TreeNode *p = Q.front();
q.pop();
if(p->left != NULL) Q.push(p->left);
if(p->right != NULL) Q.push(p->right);
}
width = width > len ? width :len;
}
return width;
}
11、二叉树直径
// 直径是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
// 注:2016考的是“根结点左右子树相隔最远的叶子结点之间的距离”