剑指Offer刷题记录 1-10

孤者浪人 提交于 2020-01-27 00:44:55

马上要面试了,把前些天在剑指Offer上刷的题再看一遍。

写上注释,算复习了,也方便以后复习。

带 * 号的为忘记怎么做的。

1. 二维数组中的查找(数组优化)

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int row_num = array.size();
        if (row_num == 0) return false;
        int col_num = array[0].size();
        // 从左下角开始找
        int i = row_num - 1, j = 0;
        while (i >= 0 && j < col_num) {
            // 对于每个位置有3种情况
            if (array[i][j] == target) return true;
            else if (array[i][j] > target) i--;
            else j++;
        }
        // 越过边界仍未找到
        return false;
    }
};
/*
class Solution {
public:
    int binarySearch(vector<int> arr, int target) {
        // 二分查找,找到返回索引,否则返回-1
        int left = 0, right = arr.size() - 1;
        int mid;
        while (left <= right) {
            mid = left + (right - left) / 2;
            if (arr[mid] == target) return mid;
            if (arr[mid] < target) left ++;
            else right --;
        }
        return -1;
    }
    
    bool Find(int target, vector<vector<int> > array) {
        int row_num = array.size();
        if (row_num == 0) return false;
        int col_num = array[0].size();
        for (int i = 0; i < row_num; i++) {
            // 对每1行执行二分查找
            if (binarySearch(array[i], target) != -1)
                return true;
        }
        return false;
    }
};
*/

2. 替换空格(字符串模拟)

class Solution {
public:
    // 从后向前处理,降低数组元素移动的复杂度
	void replaceSpace(char *str, int length) {
        int count = 0;
        // 统计空格数
        for (int i = 0; i < length; i++) 
            if (str[i] == ' ') 
                count++;
        // 从后向前
        for (int i = length - 1; i >= 0; i--) {
            // 不为空格,向后移
            if (str[i] != ' ') 
                str[i + 2 * count] = str[i];
            // 为空格,处理,并使剩余空格减一
            if (str[i] == ' ') {
                str[i + 2 * count - 2] = '%';
                str[i + 2 * count - 1] = '2';
                str[i + 2 * count] = '0';
                count--;
            }
        }
	}
};

3. 从尾到头打印链表(链表模拟)

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        // 先执行字符串翻转
        ListNode *pre = NULL, *cur = head, *post;
        while (cur != NULL) {
            // 翻转需要这4步
            post = cur->next;
            cur->next = pre;
            pre = cur;
            cur = post;
        }
        vector<int> ans;
        // 再将翻转后的1各个压入
        while (pre != NULL) {
            ans.push_back(pre->val);
            pre = pre->next;
        }
        return ans;
    }
};

4*. 重建二叉树(二叉树)

class Solution {
public:
    TreeNode* Create(vector<int> pre, int &preIndex, vector<int> mid, int left, int right) {
        // pre: 前序遍历序列
        // preIndex: 前序遍历的根节点索引
        // mid: 中序遍历序列
        // left: 当前中序序列的最左侧索引
        // right: 当前中序序列的最右侧索引
        if (left > right) return NULL;  // 当前序列没有结点,直接返回NULL
        TreeNode *root = new TreeNode(pre[preIndex++]);  // 建立根节点
        // 在中序遍历序列中找到根节点的索引
        int i;
        for (i = left; i <= right; i++) if (mid[i] == root->val) break;
        // 递归建立左右子树
        root->left = Create(pre, preIndex, mid, left, i - 1);
        root->right = Create(pre, preIndex, mid, i + 1, right);
        return root;
    }
    
    TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) {
        int preIndex = 0;
        return Create(pre, preIndex, vin, 0, pre.size() - 1);
    }
};

5. 用两个栈实现队列

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

    int pop() {
        // 当stack2为空时,将stack1中的元素送入到stack2中
        if (stack2.empty()) {
            while (!stack1.empty()) {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        // 总是从stack2中取元素返回
        int ret = stack2.top();
        stack2.pop();
        return ret;
    }

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

6. 旋转数组的最小数字(二分搜索)

class Solution {
public:
    int minNumberInRotateArray(vector<int> arr) {
        if (arr.size() == 0) return 0;
        int left = 0, right = arr.size() - 1;
        while (left < right) {
            // 每次都要检查当前序列是否是被翻转的,如果没有,则返回最左侧
            if (arr[left] < arr[right]) return arr[left];
            int mid = left + (right - left) / 2;
            // 说明mid位置处于前方子序列
            if (arr[mid] > arr[left]) left = mid + 1;
            // 说明mid位置处于后方子序列,最小元素在后方子序列,所以不能mid-1
            else if (arr[mid] < arr[left]) right = mid;
            // 如果相等,则需要遍历,如1111011
            else left ++;
        }
        return arr[left];
    }
};

7. 斐波那契数列(模拟)

class Solution {
public:
    int Fibonacci(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        int temp = 0, sum = 1;
        // 更优化的写法
        // 如 0  1  1  2  3  5  8  13  21
        for (int i = 2; i <= n; i++) {
            sum += temp, temp = sum - temp;
        }
        return sum;
    }
};

8. 跳台阶(动态规划)

class Solution {
public:
    int jumpFloor(int number) {
        if (number <= 1) return number;
        int temp = 1, sum = 1;
        // 更优化的写法
        // 1 1 2 3 5 8 13 21
        // 算第i时,sum存的是i-1处的和,temp存的是i-2处的值
        // 算完,通过运算,sum存i处的和,temp存i-1处的值
        for (int i = 2; i <= number; i++) {
            sum += temp, temp = sum - temp;
        }
        return sum;
    }
};

9. 变态跳台阶(动态规划)

class Solution {
public:
    int jumpFloorII(int number) {
        // 最优解:
        // 因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
        // 跳1级,剩下n-1级,则剩下跳法是f(n-1)
        // 跳2级,剩下n-2级,则剩下跳法是f(n-2)
        // 所以f(n)=f(n-1)+f(n-2)+...+f(1)
        // 因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
        // 所以f(n)=2*f(n-1)
        // return 1 << (number - 1);
        
        // 初始为从0级一次性到各个位置的方式数,为1
        vector<int> count(number + 1, 1);
        // i位置的方式数为由[1...i-1]位置一次性到达的方式之和
        for (int i = 2; i <= number; i++) {
            for (int j = 1; j <= i - 1; j++) {
                count[i] += count[j];
            }
        }
        return count[number];
    }
};

10. 矩形覆盖(递归)

class Solution {
public:
    int rectCover(int number) {
        if (number == 0) return 0;
        if (number == 1) return 1;
        if (number == 2) return 2;
        // 每次要么横着放2个,要么竖着放1个
        return rectCover(number - 1) + rectCover(number - 2);
    }
};

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!