• 剑指offer 1-6


    1. 二维数组中的查找

    在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
     
    分析:
    从左下角(或右上角)开始判断与要查找元素的大小,小于则向右走,大于则向上走。(类似与减而治之的思想,一次去掉一行或一列)。
    时间复杂度O(m + n)
     
    代码:
     1 class Solution {
     2 public:
     3     bool Find(int target, vector<vector<int> > array) {
     4         int s1 = array.size(), s2 = array[0].size();
     5         int i = s1 - 1, j = 0;
     6         while (i >= 0 && j < s2) {
     7             if (array[i][j] == target) {
     8                 return true;
     9             }
    10             else if (array[i][j] > target) {
    11                 i--;
    12             }
    13             else {
    14                 j++;
    15             }
    16         }
    17         return false;
    18     }
    19 };

    本题还可采用其他分治策略,后续补充。

    2. 替换空格

    请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

    分析:

    插入元素如果从前向后插入的话需要O(n^2)的时间复杂度,考虑先把空格个数算出,然后从后向前复制。

    代码:

     1 class Solution {
     2 public:
     3     void replaceSpace(char *str,int length) {
     4         int blankSz = 0;
     5         for (int i = 0; i < length; ++i) {
     6             if (str[i] == ' ') {
     7                 blankSz ++;
     8             }
     9         }
    10         int i = length - 1, j = length + 2 * blankSz - 1;
    11         while (i >= 0) {
    12             if (str[i] != ' ') {
    13                 str[j] = str[i];
    14                 j--;
    15                 i--;
    16             } else {
    17                 str[j] = '0';
    18                 str[j - 1] = '2';
    19                 str[j - 2] = '%';
    20                 i--;
    21                 j -= 3;
    22             }
    23         }
    24     }
    25 };

    3. 从尾到头打印链表

    输入一个链表,从尾到头打印链表每个节点的值

    分析:

    方法1:利用一个栈,把元素以此压栈,然后弹栈倒序输出;

    方法2:利用递归(本质利用了系统的栈)

    代码:

     1 //方法1
     2 class Solution {
     3 public:
     4     vector<int> printListFromTailToHead(ListNode* head) {
     5         stack<int> st;
     6         vector<int> result;
     7         while (head != nullptr) {
     8             st.push(head -> val);
     9             head = head -> next;
    10         }
    11         while (!st.empty()) {
    12             result.push_back(st.top());
    13             st.pop();
    14         }
    15         return result;
    16     }
    17 };
    18 
    19 //方法2
    20 class Solution {
    21 private:
    22     vector<int> result;
    23 public:
    24     vector<int> printListFromTailToHead(ListNode* head) {
    25         if (head != nullptr) {
    26             printListFromTailToHead(head -> next);
    27             result.push_back(head -> val);
    28         }
    29         return result;
    30     }
    31 };

    4. 重建二叉树

    输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

    分析:

    思路就是手动做二叉树恢复的思路,在中序遍历中找到根节点的位置,然后对左右子树各自递归。注意代码的写法,helper函数的参数设计(要传起始终止位置,不要拷贝vector)和传递(搞不清楚就举例子)即可。

    代码:

     1 class Solution {
     2 private:
     3     TreeNode* helper(const vector<int>& pre, int prevStart, int prevEnd, const vector<int>& vin, int vinStart, int vinEnd) {
     4         if (prevStart == prevEnd) {
     5             return nullptr;
     6         }
     7         if (prevEnd - prevStart == 1) {
     8             TreeNode* result = new TreeNode(pre[prevStart]);
     9             return result;
    10         } 
    11         int rootVal = pre[prevStart];
    12         TreeNode* result = new TreeNode(rootVal);
    13         int length = 0;
    14         for (int i = vinStart; i < vinEnd; ++i) {
    15             if (vin[i] != rootVal) {
    16                 length++;
    17             }
    18             else {
    19                 break;
    20             }
    21         }
    22         result -> left = helper(pre, prevStart + 1, prevStart + length + 1, vin, vinStart, vinStart + length);
    23         result -> right = helper(pre, prevStart + length + 1, prevEnd, vin, vinStart + length + 1, vinEnd);
    24         return result;
    25     }
    26 public:
    27     TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
    28         TreeNode* result = helper(pre, 0, pre.size(), vin, 0, vin.size());
    29         return result;
    30     }
    31 };

    5. 用两个栈实现队列

    用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

    分析:

    思路1 stack1用来push, stack2用来pop(),每次pop()完把数据倒回到stack1中,保证满足队列顺序,但效率比较低;

    思路2 stack1用来push, stack2用来pop(),  每次pop()前判定stack2是否为空,如果为空则将stack1中元素均倒入stack2,然后再在stack2中pop(),不空直接pop()stack2

    代码:

     1 //方法1
     2 class Solution
     3 {
     4 public:
     5     void push(int node) {
     6         stack1.push(node);
     7     }
     8  
     9     int pop() {
    10         while (!stack1.empty()) {
    11             stack2.push(stack1.top());
    12             stack1.pop();
    13         }
    14         int result = stack2.top();
    15         stack2.pop();
    16         while (!stack2.empty()) {
    17             stack1.push(stack2.top());
    18             stack2.pop();
    19         }
    20         return result;
    21          
    22     }
    23  
    24 private:
    25     stack<int> stack1;
    26     stack<int> stack2;
    27 };
    28 
    29 //方法2
    30 class Solution
    31 {
    32 public:
    33     void push(int node) {
    34         stack1.push(node);
    35     }
    36 
    37     int pop() {
    38         if (stack2.empty()) {
    39             while (!stack1.empty()) { 
    40                 stack2.push(stack1.top());
    41                 stack1.pop();
    42             }
    43         }
    44         int result = stack2.top();
    45         stack2.pop();
    46         return result;
    47         
    48     }
    49 
    50 private:
    51     stack<int> stack1;
    52     stack<int> stack2;
    53 };

    6. 旋转数组的最小数字

    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

    分析:

    思路1 二分搜索,用套路写就行,注意的是,其实由于更新start的条件只能在array[mid] > target时,start = mid,所以出循环后array[start]肯定不是解,可以不加那个判断;

    思路2 可以用递归,注意分开两个区间的时候,有可能一个区间是非旋转的,所以递归终止条件是

            if (rotateArray[0] <= rotateArray[n - 1]) {
                return rotateArray[0];
            }

    可以同时处理两种情况。

    代码:

     1 class Solution {
     2 public:
     3     int minNumberInRotateArray(vector<int> rotateArray) {
     4         int start = 0, end = rotateArray.size() - 1;
     5         while (start + 1 < end) {
     6             int mid = start + (end - start) / 2;
     7             if (rotateArray[mid] == rotateArray[0]) {
     8                 start = mid;
     9             }
    10             else if (rotateArray[mid] < rotateArray[0]) {
    11                 end = mid;
    12             }
    13             else {
    14                 start = mid;
    15             }
    16         }
    17         return rotateArray[end];
    18     }
    19 };
  • 相关阅读:
    Vue 组件的基础介绍
    Java web中的路径问题
    个人网站的使用路线
    EL表达式
    jsp
    状态管理和作用域对象
    servlet
    jsp session获取问题
    关于jsp页面中接收二维数组
    个人网站开发(二)
  • 原文地址:https://www.cnblogs.com/wangxiaobao/p/6213201.html
Copyright © 2020-2023  润新知