方向2学习:学习剑指Offer
昨晚半夜到的杭州,深圳到杭州的高铁真心慢,这么多年一直慢(苦笑)浪费了一天(哭笑)
在外地手上没资料,新买的剑指offer还要两天到。先看网上的题吧。
网络例题1:
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
Input:
{2, 3, 1, 0, 2, 5}
Output:
2
网上解题思路:要求复杂度为 O(N) + O(1),也就是时间复杂度 O(N),空间复杂度 O(1)。因此不能使用排序的方法,也不能使用额外的标记数组。牛客网讨论区这一题的首票答案使用 nums[i] + length 来将元素标记,这么做会有加法溢出问题。
这种数组元素在 [0, n-1] 范围内的问题,可以将值为 i 的元素调整到第 i 个位置上。
我的思考经历:如果不对复杂度做要求,最先想到的就是 额外的标记数组方法,适用于各种重复数字查找。但是研究了答案后发现,题目给出的0到n-1范围是有重要意义的。
当限定了范围后元素值只能在元素数量范围内,换句话讲元素值都可以指定一个元素位置。看例子中2 3 1 0 2 5。这告诉了我们什么信息呢(这个地方真的想了很久),
信息1、不重复的情况下每一个元素都能单独指定一个位置;2、不重复的情况下每一个位置必定都有元素去指定。3、当有出现重复的情况时必定有元素指向的位置相同且有相同值得元素占用多个位置。
这时候答案已经快出来了,但是我还是在多次运行代码后才理解。逻辑大佬们肯定都想到了,但是我不说,嘿嘿。方代码给你们看。自己验证一下想的对不对。
#include <iostream>
using namespace std;
bool duplicate(int nums[], int length, int duplication[]);
void swap(int nums[], int i, int j);
int main()
{
int tem[] = { 2,3,1,0,2,5};
int tem2[1] = { 999 };
int len = sizeof(tem);
bool boolNew=duplicate(tem, len, tem2);
cout << "Hello World!\n"<< boolNew<<endl;
}
bool duplicate(int nums[], int length, int duplication[]) {
if (nums == NULL || length <= 0)
return false;
for (int i = 0; i < length; i++) {
while (nums[i] != i) {
if (nums[i] == nums[nums[i]]) {
duplication[0] = nums[i];
cout << i <<" nums[i]="<< nums[i] << endl;
return true;
}
cout << "1 [i]=" << i << " nums[i]=" << nums[0] << nums[1] << nums[2] << nums[3] << nums[4] << nums[5] << nums[6] << nums[7] << endl;
swap(nums, i, nums[i]);
cout << "2 [i]=" << i << " nums[i]=" << nums[0] << nums[1] << nums[2] << nums[3] << nums[4] << nums[5] << nums[6] << nums[7] << endl;
}
}
return false;
}
void swap(int nums[], int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
是不是猫舍蹲开,脑海中叫到:不就是排序对比嘛,用了两次循环,也没见高级到哪里。
真的是做了排序吗,再换一窜数据进去试试{0,3,2,4,4,4,6,5 },多次尝试后你会发现如果目的是排序就舍本逐末了。也有朋友逐渐领悟,甚至在给出答案前就想到了,我们需要做的是将元素放到他的值指定的位置,出现重复时就得到我们想要的结果了。
再做一次解释,运行代码得到的排序结果并不是结题过程必须达到的目的,只是在得出结果时有时刚好也完成了排序。而代码中实现排序的部分没有0到n-1的限制时,也无法实现一个萝卜一个坑的排序。这道题花了我两个小时,高级之处不只这些。另外,答案还是有漏洞的,当没有重复时数据会溢出,所以别照抄。有心的朋友还是解析看看吧。
网络例题2:
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
Consider the following matrix:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
Given target = 5, return true.
Given target = 20, return false.
太简单了,答案也没什么可说的,直接上代码
bool Find(int (*nums)[5][5], int length) {
if (*nums == NULL || sizeof(*nums) == 0 || sizeof((*nums)[0]) == 0)
return false;
int rows = sizeof((*nums)) / sizeof((*nums)[0]), cols = sizeof((*nums)[0]) / 4;
int r = 0, c = cols - 1; // 从右上角开始
while (r <= rows - 1 && c >= 0) {
if (length == (*nums)[r][c])
return true;
else if (length > (*nums)[r][c])
r++;
else
c--;
}
return false;
}
亮点是从右上角开始对比,当输入值比一行的最大值大时跳过本行,后面运行忽略已跳过的行。当比一列的最小值小跳过本列,后面运行忽略已跳过的列(重左下角开对比则反向对比,左上角和右下角只能逐个对比)
网络例题3:
将一个字符串中的空格替换成 “%20”。
Input:
"We Are Happy"
Output:
"We%20Are%20Happy"
网上有很多方法,我还是觉得用string最简单
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<string>
using namespace std;
int main()
{
string tem = "a b c d e f g";//时隔多日看到一个函数完美解决tem.replace(" ","%20")
for (int i = 0; i < tem.length(); i++) {
if (tem[i]==' ')
{
tem.replace(i,1,"");
cout << "tem-' '=" << tem << endl;
tem.insert(i, "%20");
cout << "tem+%20=" << tem << endl;
i++;
}
}
cout << " " << tem << endl;
}
网络例题4:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
这题思路只有两种情况:中序的下一个节点最先应该是当前节点的右子树最左值,当没有右子树时下一个节点就是根节点中第一个作为左值的节点的父节点。
TreeLinkNode GetNext(TreeLinkNode pNode) {
if (pNode.right != null) {
TreeLinkNode node = pNode.right;
while (node.left != null)
node = node.left;
return node;
} else {
while (pNode.next != null) {
TreeLinkNode parent = pNode.next;
if (parent.left == pNode)
return parent;
pNode = pNode.next;
}
}
return null;
}
12点了不搞了。明天去西溪湿地转转,摸鱼啦!!