算法刷题日记day3

118 阅读2分钟

剑指offer

1.旋转数组中的最小数字

描述:有一个长度为 n 的非降序数组,把最开始的若干个元素搬到数组的末尾,变成一个旋转数组,求旋转后数组的最小值, 空间复杂度:O(1) ,时间复杂度:O(logn)

思路:二分法

int minNumberInRotateArray(vector<int> rotateArray) {
    if (rotateArray.size() == 0) return 0;//起始条件判断
    int first = 0, last = rotateArray.size() - 1;
    while (first < last) { // 最后剩下一个元素,即为答案
        if (rotateArray[first] < rotateArray[last]) { 
        // 如果左端点值小于右端点值,根据初始给定的非递减数组的条件得知,提前退出
            return rotateArray[first];
        }
        int mid = (first+last)/2;
        //情况一:把右端元素作为target,如果中值大于target,target一定在右半区
        if (rotateArray[mid] > rotateArray[last]) first=mid+1;
        //情况二:如果中值小于target,target一定在左半区,中值有可能是target
        else if (rotateArray[mid] < rotateArray[last]) last=mid;
        //情况三:例如{1,1,1,1,1},则缩小last范围,也能得出结论
        else last--;
    }
    return rotateArray[first];
}

2.矩阵中的路径

思路:回溯法

bool hasPath(vector<vector<char> >& matrix, string word) {
    for (int i = 0; i < matrix.size(); i++) 
    {
        for (int j = 0; j < matrix[0].size(); j++)
        {
            //从[i,j]这个坐标开始查找
            if (dfs(matrix, word, i, j, 0))
                return true;
        }
    }
    return false;
}
bool dfs(vector<vector<char>> matrix, string word, int i, int j, int index) {
//边界的判断,如果越界直接返回false。index表示的是查找到字符串word的第几个字符,
//如果这个字符不等于matrix[i][j],说明验证这个坐标路径是走不通的,直接返回false
if (i >= matrix.size() || i < 0 || j >= matrix[0].size() || j < 0 || matrix[i][j] != word[index])
    return false;
//如果word的每个字符都查找完了,直接返回true
if (index == word.size() - 1)
    return true;
//把当前坐标的值保存下来,为了在最后复原
char tmp = matrix[i][j];
//然后修改当前坐标的值
matrix[i][j] = '.';
//走递归,沿着当前坐标的上下左右4个方向查找
bool res = dfs(matrix, word, i + 1, j, index + 1)
        || dfs(matrix, word, i - 1, j, index + 1)
        || dfs(matrix, word, i, j + 1, index + 1)
        || dfs(matrix, word, i, j - 1, index + 1);
//递归之后再把当前的坐标复原
matrix[i][j] = tmp;
return res;
}

3.二进制中1的个数

描述:输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。

 int  NumberOf1(int n) {
    int ans = 0;
    while (n != 0) {
        ++ans;
        n = n & (n-1);//每次执行得到的二进制数都少一个1
    }
    return ans;
 }

4.数值的整数次幂

法一:暴力法

double Power(double b, int n) {
    if (n < 0) {
        b = 1 / b;
        n = -n;
    }
    double ret = 1.0;
    for (int i=0; i<n; ++i) ret *= b;
    return ret;
}

法二:快速幂法

double Power(double b, int n) {
    if (n < 0) {//负数底倒指反
        b = 1 / b;
        n = -n;
    }
    double x = b; // 记录x^0, x^1, x^2 ...
    double ret = 1.0;
    while (n) {
        if (n&1) {
            ret *= x; // 二进制位数是1的,乘进答案。
        }
        x *= x;
        n >>= 1;
    }
    return ret;
}

5.删除链表节点

ListNode* deleteNode(ListNode* head, int val) {
    ListNode * phead=new ListNode(-1);
    phead->next=head;
    if(!head) return head;
    if(head->val==val) phead->next=phead->next->next;
    while(head->next)
    {
        if(head->next->val==val)
            head->next=head->next->next;
        else
            head=head->next;
    }
    return phead->next;
}

6.打印从1到最大的n位数

vector<int> printNumbers(int n) {
    // write code here
    vector<int> v;
    int m=1;
    for(int i=0;i<n;i++) m*=10;
    for(int i=1;i<m;i++)
        v.push_back(i);
    return v;
}

7.调整数组顺序,使奇数位于偶数前面,并报持相对位置不变

法一:借助辅助数组

法二:直接在数组中调整位置 时间复杂度O(n^2),空间复杂度O(1)。

vector<int> reOrderArray(vector<int>& array) {
    int index=0;
    for(int i=0;i<array.size();i++)
    {
        if(array[i]%2!=0)
        {
            int tmp=array[i];
            for(int j=i;j>index;j--)//注意移动数组元素时,要注意顺序,避免一个元素全部覆盖
            {
                array[j]=array[j-1];
            }
            array[index]=tmp;
            index++;
        }
    }
    return array;
}

8.二叉树的镜像

法一:借助辅助栈

TreeNode* Mirror(TreeNode* pRoot) {
    if(!pRoot) return nullptr;
    stack<TreeNode *> st;
    TreeNode * tmp;
    st.push(pRoot);
    while(!st.empty())
    {
        TreeNode* node=st.top();
        st.pop();
        if(node->left) st.push(node->left);
        if(node->right) st.push(node->right);
        tmp = node->left;//交换左右子节点
        node->left=node->right;
        node->right=tmp;
    }
    return pRoot;
}

法二:递归

TreeNode* Mirror(TreeNode* pRoot) {
    if(pRoot) //判断边界条件,是否为空树 空树递归结束
    {
        TreeNode* temp;//定义一个缓冲指针
        temp=pRoot->left;//缓冲左树
        pRoot->left=pRoot->right;//左树等于右树
        pRoot->right=temp;//右树等于左树(缓冲)
        pRoot->left=Mirror(pRoot->left);//递归左树
        pRoot->right=Mirror(pRoot->right);//递归右树
    }
    return pRoot;
}

整合版

TreeNode* Mirror(TreeNode* pRoot) {
    if(pRoot) //判断边界条件,是否为空树 空树递归结束
    {
        TreeNode* temp;//定义一个缓冲指针
        temp=Mirror(pRoot->left);//缓冲并镜像左树
        pRoot->left=Mirror(pRoot->right);//左树等于右树
        pRoot->right=temp;//右树等于左树(缓冲)
    }
    return pRoot;
}