算法刷题日记DAY2

95 阅读3分钟

剑指offer(第二版)

1.二维数组中的查找

bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
    int row=array.size()-1;//从左下角开始找
    int cul=0;
    if(array.size()==0) return false;
    while(row >= 0 && cul < array[0].size())
    {
        int k=array[row][cul];
        if(k==target) return true;
        else if(k>target) row--;  //当前值大于被寻找值,往左寻找
        else cul++;  //否则往上寻找
    }
    return false;
}

2.数组中的重复数字

描述:输出数组中的重复数字,如果没有,返回-1

int duplicate(vector<int>& numbers) {
    unordered_map<int, int> map;//哈希表
    for(auto i:numbers)
    {
        map[i]++;//发现重复数字,key值+1,如果没有,自动创造键值对存入哈希表中
    }
    for(int i=0;i<map.size();i++)//遍历map,找到第一个重复数字,返回
    {
        if(map[i]>1)
            return i;
    }
    return -1;
}

3.替换空格

string replaceSpace(string s) {
    string str="";
    for(int i=0;i<s.size();i++)
    {
        if(s[i]==' ')
        {
            str+=('%');
            str+=('2');
            str+=('0');
        }
        else str+=s[i];
    }
    return str;
}

4.从尾到头打印链表

思路:定义一个数组接收所有节点的权值,反转数组并返回

vector<int> printListFromTailToHead(ListNode* head) {
    vector<int> v;
    while(head)
    {
        v.push_back(head->val);
        head=head->next;
    }
    reverse(v.begin(), v.end());
    return v;
}

5.重建二叉树

描述:给出一棵树的前序遍历和中序遍历数组,重建出这颗二叉树

TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
    return rebuild(pre, 0, pre.size()-1, vin, 0, vin.size()-1);
}

TreeNode* rebuild(vector<int>& pre, int pre_left, int pre_right, 
                  vector<int>& vin, int vin_left, int vin_right)
                  //递归函数,参数:前序遍历数组,前序遍历数组左下标,右下标
                                   中序遍历数组,前序遍历数组左下标,右下标
{
    if (pre_left > pre_right||vin_left > vin_right) return nullptr;
    //递归结束条件:左下标大于右下标,说明数组遍历完成
    TreeNode* root = new TreeNode(pre[pre_left]);
    //根节点值一定等于前序遍历数组的第一个数字
    for (int i=vin_left; i<=vin_right; ++i)
    {
    //关键点:利用for循环找到前序遍历中根节点的数值在中序遍历数组中的位置,那么往左的所有节点为左子树,往右为右子树
        if (vin[i] == root->val) {
        //如果中序遍历数组第i个数等于当前节点的值,递归构建左子树和右子树
            root->left = rebuild(pre, pre_left+1, pre_left+i-vin_left, 
                                 vin, vin_left, i-1);
            root->right = rebuild(pre, pre_left+i-vin_left+1, pre_right, 
                                 vin, i+1, vin_right);
            break;
        }
    }
    return root;
}

6.二叉树的下一个节点

描述:给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。

法一:暴力法

void in_order(TreeLinkNode * root, vector<TreeLinkNode*> &v)//中序递归遍历函数
{
    if(!root) return;
    in_order(root->left, v);
    v.push_back(root);
    in_order(root->right, v);
}

TreeLinkNode* GetNext(TreeLinkNode* pNode) {
    TreeLinkNode * root = nullptr;
    TreeLinkNode * tmp = pNode;
    while(tmp)    //求出整棵树的根节点
    {
        root=tmp;
        tmp=tmp->next;
    }
    vector<TreeLinkNode*> v;
    in_order(root, v);    //把所有节点放入容器中
    for(int i=0;i<v.size();i++)    //利用for循环在vector中找到当前节点
    {
        if(v[i]==pNode && i+1!=v.size()) return v[i+1];//return下一节点
    }
    return nullptr;
}

法二:最优解法

牢牢抓住中序遍历左根右的核心思想寻找下一节点

TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
    if (!pNode) return pNode;//如果根节点不存在,返回空
    if (pNode->right)//第一类:该节点有孩子
    {
        pNode = pNode->right;//右子树的左子树不存在,返回右子树的根节点
        while (pNode->left)//右子树的左子树存在,一路向左,返回最左叶子节点
        {
            pNode = pNode->left;
        }
        return pNode;
    }
    while (pNode->next)//第二类:该节点有父亲,并且在左子树中
    {
        TreeLinkNode *root = pNode->next;//令指针指向其父亲节点
        if (root->left == pNode)//如果该节点为父亲的左孩子,返回父亲
        {
            return root;
        }
        pNode = pNode->next;//如果该节点为父亲的右孩子,一路向上,找到根节点
    }
    return nullptr;//该节点为最右叶子节点
}

7.用两个栈实现队列

注意:pop操作需要分类,若stack2中没有元素,才要stack2.push(stack1.top());

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        if(stack2.empty())
        {
            while(!stack1.empty())
            {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        int ret=stack2.top();
        stack2.pop();
        return ret;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

8.斐波那契数列

时间复杂度O(n),空间复杂度O(1)

int Fibonacci(int n) {
    int a = 1 , b = 1 , c = 1;
    for (int i = 3 ; i <= n ; i ++) {
        c = a+b , a = b , b = c;
    }
    return c;
}