剑指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 };
时间: 2024-12-13 03:46:53

剑指offer 1-6的相关文章

【剑指offer】Q38:数字在数组中出现的次数

与折半查找是同一个模式,不同的是,在这里不在查找某个确定的值,而是查找确定值所在的上下边界. def getBounder(data, k, start, end, low_bound = False): if end < start : return -1 while start <= end: mid = ( start + end ) >> 1 if data[ mid ] > k: end = mid - 1 elif data[ mid ] < k: star

【剑指offer】树的子结构

转载请注明出处:http://blog.csdn.net/ns_code/article/details/25907685 剑指offer第18题,九度OJ上测试通过! 题目描述: 输入两颗二叉树A,B,判断B是不是A的子结构. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行一个整数n,m(1<=n<=1000,1<=m<=1000):n代表将要输入的二叉树A的节点个数(节点从1开始计数),m代表将要输入的二叉树B的节点个数(节点从1开始计数).

【剑指offer】二叉树的镜像

转载请注明出处:http://blog.csdn.net/ns_code/article/details/25915971 题目描述: 输入一个二叉树,输出其镜像. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000,n代表将要输入的二叉树节点的个数(节点从1开始编号).接下来一行有n个数字,代表第i个二叉树节点的元素的值.接下来有n行,每行有一个字母Ci.Ci='d'表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号.C

【剑指offer】数组中仅仅出现一次的数字(1)

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27649027 题目描写叙述: 一个整型数组里除了两个数字之外,其它的数字都出现了两次.请敲代码找出这两个仅仅出现一次的数字. 输入: 每一个測试案例包括两行: 第一行包括一个整数n,表示数组大小.2<=n <= 10^6. 第二行包括n个整数,表示数组元素,元素均为int. 输出: 相应每一个測试案例.输出数组中仅仅出现一次的两个数.输出的数字从小到大的顺序. 例子输入: 8 2 4

牛客网上的剑指offer题目

题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 题目:请实现一个函数,将一个字符串中的空格替换成"%20" 两种方法实现:输入一个链表,从尾到头打印链表每个节点的值 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 剑指offer 斐波那契数列 一只青蛙一次可以跳上1级台阶,也可以跳上2级--它也可以跳上n级.求该青蛙跳上一个

剑指Offer——如何做好自我介绍

剑指Offer--如何做好自我介绍 前言 自我特点+经历梳理 ??各位老师好,我叫某某某,研究生三年级,就读于某某大学信息科学与工程学院软件工程专业.主要使用的开发语言是Java,熟悉基本数据结构和基本算法实现:熟悉MySQL数据库:掌握Linux基本操作命令:所参与的主要项目有"立马送药","鲜花礼品网","基于Android实现的购彩系统"和"我看看"购物分享Android APP.其中,"立马送药"的

剑指Offer——Trie树(字典树)

剑指Offer--Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高. Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.可见,优

【剑指Offer面试题】二维数组中的查找

下决心AC所有剑指offer面试题. 九度OJ面试题地址:http://ac.jobdu.com/hhtproblems.php 书籍:何海涛--<剑指Offer:名企面试官精讲典型编程题> 对于面试题,面试官往往更希望我们能提出优化方法,这样更能体现我们的思维能力以及传说中的"内功".所以做剑指offer要着重训练这方面,多总结多细究,总是有好处的.加油~ 二维数组中的查找 时间限制:1 秒内存限制:32 兆 特殊判题:否提交:19005解决:3642 题目描述: 在一个

[剑指Offer]12.二进制中1的个数

题目 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路 把一个整数减去1,再和原整数做与运算,会把整数最右边一个1变成0.那么一个整数的二进制表示中有多少个1,就可以进行多次这样的操作. 代码 /*--------------------------------------- * 日期:2015-07-20 * 作者:SJF0115 * 题目: 12.二进制中1的个数 * 结果:AC * 网址:http://www.nowcoder.com/books/coding-int

C++中求数组连续子向量的最大和(牛客剑指offer)

/////////////////////////////////////////////////////////////////// //HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学. //今天测试组开完会后,他又发话了:在古老的一维模式识别中, //常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决. //但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢? //例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开