《盘点那些秀你一脸的秒天秒地算法》(1)

本系列坚持格式:1个抖机灵算法+2个较简单但是天秀的算法+1个较难天秀算法。

 

bogo排序

Bogo排序(Bogo-sort),又被称为猴子排序,是一种恶搞排序算法。

将元素随机打乱,然后检查其是否符合排列顺序,若否,则继续进行随机打乱,继续检查结果,直到符合排列顺序。
Bogo排序的最坏时间复杂度为O(∞),一辈子也不能输出排序结果,平均时间复杂度为O(n·n!)。

这让我想到了另一个理论:猴子理论,只要让一只猴子一直敲打计算机,理论上会有一天,它能敲出一本圣经出来,但是这个概率小到宇宙毁灭也很难敲出来。。

真的不知道这个排序应该叫做天才还是垃圾哈哈哈,但是闲的没事的我就把他实现出来了。

public class Main {public static void main(String[] args) {int[] arr = { 9,8,7,6,5,4,3,2,1};System.out.println("排序次数" + bogo(arr));for (int i : arr) {System.out.print(i + " ");}}public static int bogo(int[] arr) {int count = 0;while (!isOrdered(arr)) {shuffle(arr);count++;}return count;}// 判断是否有序方法public static boolean isOrdered(int[] arr) {for (int i = 1; i < arr.length; i++) {if (arr[i - 1] > arr[i]) {return false;}}return true;}// 随机排序方法public static void shuffle(int[] arr) {int temp;for (int i = 0; i < arr.length; i++) {int j = (int) (Math.random() * arr.length);temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}}

9是中国最大的数字嘛,我就把数组长度设为9,结果平均排序次数要60万次,不知道我的运气怎么样哈哈,你们也试试吧?

 

然而,有个看似笑话的方法声称可以用O(n)实现Bogo排序,依照量子理论的平行宇宙解释,使用量子随机性随机地重新排列元素,不同的可能性将在不同的宇宙中展开,总有一种可能猴子得到了正确的顺序,量子计算机找到了这个宇宙后,就开始毁灭其他排序不成功的宇宙,剩下一个观察者可以看到的正确顺序的宇宙。

如果想要迈出这个看似荒诞,但令人无比兴奋的"高效算法"的第一步,请先证明"平行宇宙解释"的正确性。

位运算

关于位运算有很多天秀的技巧,这里举一个例子。

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]输出: 1
示例 2:

输入: [4,1,2,1,2]输出: 4

思路:拿map,set,都不符合要求,那怎么办呢?

我们知道什么数字和自己异或,都等于0.

什么数字和0异或,都等于它本身,

异或又符合交换律

所以全部异或一遍,答案就是那个出现一次的数字。

class Solution {public int singleNumber(int[] nums) {int ans = 0;for(int i :nums)ans ^= i;return ans;}
}

有没有被秒了?

 

打擂台

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

把狂野般的思绪收一收,咱们来看看最优解。

class Solution {public int majorityElement(int[] nums) {int count = 0;//当前答案出现的次数Integer candidate = null;//答案for (int num : nums) {if (count == 0) candidate = num;count += (num == candidate) ? 1 : -1;}return candidate;}
}

我来解释一下策略:记录当前的答案candidate ,记录count。这时,我们遍历了一个新的数字,如果和candidate 一样,我们就让count+1,否则让count-1.如果count变成了0,那candidate 就下擂台,换新的擂主(数字)上,也就是说把candidate 更新成新的数字,count也更新成1.

最后在擂台上的一定是答案。

肯定有人怀疑这个做法的正确性吧?我就来说一下它为啥对?

首先,我们想像一下对最终隐藏答案ans最不利的情况:每个其他数字全部都打擂这个答案ans,那ans的count最后也会剩1,不会被打下来。

正常情况呢?其他数字还会互相打擂,这些数字如此“内耗”,又怎么能斗得过最终答案ans呢?对不对?

 

morris遍历

通常,实现二叉树的前序(preorder)、中序(inorder)、后序(postorder)遍历有两个常用的方法:一是递归(recursive),二是使用栈实现的迭代版本(stack+iterative)。这两种方法都是O(n)的空间复杂度(递归本身占用stack空间或者用户自定义的stack),我分别给出一个例子

递归:

void PreorderTraversal( BinTree BT )
{if(BT==NULL)return ;printf(" %c", BT->Data);PreorderTraversal(BT->Left);PreorderTraversal(BT->Right);
}

非递归:

*p=root;
while(p || !st.empty())
{if(p)//非空{//visit(p);进行操作st.push(p);//入栈p = p->lchild;左} else//空{p = st.top();//取出st.pop();p = p->rchild;//右}
}

为啥这个O(n)的空间就是省不掉呢?因为我们需要空间来记录之前的位置,好在遍历完了可以回到父节点。所以这个空间是必须的!如下图:

比如我们遍历2,想遍历4,这时候我们要保证遍历完4以后,还能回到2,我们好去继续遍历5等等结点,所以必须花空间记录。

 

但是,还就有这么一种算法,能实现空间O(1)的遍历,服不服。

你们可能会问,你刚说的,必须有空间来记录路径,怎么又可以不用空间了呢?

这就是morris遍历,它其实是利用了叶子节点大量的空余空间来实现的,只要把他们利用起来,我们就可以省掉额外空间啦。

我们不说先序中序后序,先说morris遍历的原则:

1、如果没有左孩子,继续遍历右子树,比如:

这个2就没有左孩子,这时直接遍历右孩子即可。

2、如果有左孩子,找到左子树最右节点。

比如上图,6就是2的最右节点。

    1)如果最右节点的右指针为空(说明第一次遇到),把它指向当前节点,当前节点向左继续处理。

修改后:

    2)如果最右节点的右指针不为空(说明它指向之前结点),把右指针设为空,当前节点向右继续处理。

 

这就是morris遍历。

请手动模拟深度至少为4的树的morris遍历来熟悉流程。

下面给出实现:

定义结点:

	public static class Node {public int value;Node left;Node right;public Node(int data) {this.value = data;}}

先序:(完全按规则写就好。)

//打印时机(第一次遇到):发现左子树最右的孩子右指针指向空,或无左子树。public static void morrisPre(Node head) {if (head == null) {return;}Node cur1 = head;Node cur2 = null;while (cur1 != null) {cur2 = cur1.left;if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {cur2 = cur2.right;}if (cur2.right == null) {cur2.right = cur1;System.out.print(cur1.value + " ");cur1 = cur1.left;continue;} else {cur2.right = null;}} else {System.out.print(cur1.value + " ");}cur1 = cur1.right;}System.out.println();}

morris在发表文章时只写出了中序遍历。而先序遍历只是打印时机不同而已,所以后人改进出了先序遍历。至于后序,是通过打印所有的右边界来实现的:对每个有边界逆序,打印,再逆序回去。注意要原地逆序,否则我们morris遍历的意义也就没有了。

完整代码: 

public class MorrisTraversal {public static void process(Node head) {if(head == null) {return;}// 1//System.out.println(head.value);process(head.left);// 2//System.out.println(head.value);process(head.right);// 3//System.out.println(head.value);}public static class Node {public int value;Node left;Node right;public Node(int data) {this.value = data;}}//打印时机:向右走之前public static void morrisIn(Node head) {if (head == null) {return;}Node cur1 = head;//当前节点Node cur2 = null;//最右while (cur1 != null) {cur2 = cur1.left;//左孩子不为空if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {cur2 = cur2.right;}//找到最右//右指针为空,指向cur1,cur1向左继续if (cur2.right == null) {cur2.right = cur1;cur1 = cur1.left;continue;} else {cur2.right = null;}//右指针不为空,设为空}System.out.print(cur1.value + " ");cur1 = cur1.right;}System.out.println();}//打印时机(第一次遇到):发现左子树最右的孩子右指针指向空,或无左子树。public static void morrisPre(Node head) {if (head == null) {return;}Node cur1 = head;Node cur2 = null;while (cur1 != null) {cur2 = cur1.left;if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {cur2 = cur2.right;}if (cur2.right == null) {cur2.right = cur1;System.out.print(cur1.value + " ");cur1 = cur1.left;continue;} else {cur2.right = null;}} else {System.out.print(cur1.value + " ");}cur1 = cur1.right;}System.out.println();}//逆序打印所有右边界public static void morrisPos(Node head) {if (head == null) {return;}Node cur1 = head;Node cur2 = null;while (cur1 != null) {cur2 = cur1.left;if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {cur2 = cur2.right;}if (cur2.right == null) {cur2.right = cur1;cur1 = cur1.left;continue;} else {cur2.right = null;printEdge(cur1.left);}}cur1 = cur1.right;}printEdge(head);System.out.println();}
//逆序打印public static void printEdge(Node head) {Node tail = reverseEdge(head);Node cur = tail;while (cur != null) {System.out.print(cur.value + " ");cur = cur.right;}reverseEdge(tail);}
//逆序(类似链表逆序)public static Node reverseEdge(Node from) {Node pre = null;Node next = null;while (from != null) {next = from.right;from.right = pre;pre = from;from = next;}return pre;}public static void main(String[] args) {Node head = new Node(4);head.left = new Node(2);head.right = new Node(6);head.left.left = new Node(1);head.left.right = new Node(3);head.right.left = new Node(5);head.right.right = new Node(7);morrisIn(head);morrisPre(head);morrisPos(head);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/444702.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《盘点那些秀你一脸的秒天秒地算法》(3)

斐波那契之美 斐波那契数列&#xff08;Fibonacci sequence&#xff09;&#xff0c;又称黄金分割数列、因数学家列昂纳多斐波那契&#xff08;Leonardoda Fibonacci&#xff09;以兔子繁殖为例子而引入&#xff0c;故又称为“兔子数列”。 这个数列就是1、1、2、3、5、8、13…

《盘点那些秀你一脸的秒天秒地算法》(4)

防止新手错误的神级代码 #define ture true #define flase false #difine viod void #define mian main #define &#xff1b; ; 以后有新手问题就把这几行代码给他就好啦。 不用额外空间交换两个变量 a 5 b 8 #计算a和b两个点到原点的距离之和&#xff0c;并且赋值给…

为啥用redis解决会话呢?

什么是会话&#xff1f; 会话可简单理解为&#xff1a;用户开一个浏览器&#xff0c;点击多个超链接&#xff0c;访问服务器多个web资源&#xff0c;然后关闭浏览器&#xff0c;整个过程称之为一个会话。 •会话过程中要解决的一些问题&#xff1f; –每个用户不可避免各自会…

听说你还在纠结自己没访问量?成不了“博客专家”?

一、提高浏览量的技巧 相信很多人都这么想过&#xff1a;“我文章写的这么好&#xff0c;怎么就没人看呢&#xff1f;”&#xff1b; 或者这样想过&#xff1a;“这文章写得明明比我烂很多&#xff0c;凭什么这么多浏览量&#xff1f;”&#xff1b; 虽然在我看来这是极其严…

关系数据库——范式/反范式的利弊权衡和建议

范式&#xff08;避免数据冗余和操作异常&#xff09; 函数依赖 A->B A和B是两个属性集&#xff0c;来自同一关系模式&#xff0c;对于同样的A属性值&#xff0c;B属性值也相同 平凡的函数依赖 X->Y&#xff0c;如果Y是X的子集 非平凡的函数依赖 X->Y&#xff…

pytorch学习入门 (二) Variable(变量)

Variable&#xff08;变量&#xff09; autograd.Variable 是包的核心类. 它包装了张量, 并且支持几乎所有的操作. 一旦你完成了你的计算, 你就可以调用 .backward() 方法, 然后所有的梯度计算会自动进行. 你还可以通过 .data 属性来访问原始的张量, 而关于该 variable&#…

leetcode1033. 移动石子直到连续

三枚石子放置在数轴上&#xff0c;位置分别为 a&#xff0c;b&#xff0c;c。 每一回合&#xff0c;我们假设这三枚石子当前分别位于位置 x, y, z 且 x < y < z。从位置 x 或者是位置 z 拿起一枚石子&#xff0c;并将该石子移动到某一整数位置 k 处&#xff0c;其中 x &…

pytorch学习 训练一个分类器(五)

训练一个分类器 就是这个, 你已经看到了如何定义神经网络, 计算损失并更新网络的权重. 现在你可能会想, 数据呢? 一般来说, 当你不得不处理图像, 文本, 音频或者视频数据时, 你可以使用标准的 Python 包将数据加载到一个 numpy 数组中. 然后你可以将这个数组转换成一个 to…

【软考中级】网络工程师:8.网络安全

本章考察内容比较广泛&#xff0c;考题对知识点都会有所涉及。 8.1 网络安全的基本概念 8.1.1 网络安全威胁的类型 窃听 这种情况发生在广播式网络系统中&#xff0c;每个节点都可以读取数据&#xff0c;实现搭线窃听、安装通信监视器和读取网上的信息等。 假冒 当一个实体…

caffe网络结构图绘制

绘制网络图通常有两种方法&#xff1a; 一种是利用python自带的draw_net.py&#xff0c;首先安装两个库&#xff1a; sudo apt-get install graphviz sudo pip install pydot 接下来就可以用python自带的draw_net.py文件来绘制网络图了。 draw_net.py执行时带三个参数&…

理解Caffe的网络模型

目录 1. 初见LeNet原始模型2. Caffe LeNet的网络结构3. 逐层理解Caffe LeNet 3.1 Data Layer3.2 Conv1 Layer3.3 Pool1 Layer3.4 Conv2 Layer3.5 Pool2 Layer3.6 Ip1 Layer3.7 Relu1 Layer3.8 Ip2 Layer3.9 Loss Layer 1. 初见LeNet原始模型 Fig.1. Architecture of original …

caffe开始训练自己的模型(转载并验证过)

学习caffe中踩了不少坑&#xff0c;这里我参考了此博主的文章&#xff0c;并体会到了如何训练自己的模型&#xff1a;http://www.cnblogs.com/denny402/p/5083300.html 学习caffe的目的&#xff0c;不是简单的做几个练习&#xff0c;最终还是要用到自己的实际项目或科研中。因…

图像拼接(一):柱面投影+模板匹配+渐入渐出融合

这种拼接方法的假设前提是&#xff1a;待拼接的两幅图像之间的变换模型是平移模型&#xff0c;即两幅图像同名点位置之间只相差两个未知量&#xff1a;ΔxΔx 和ΔyΔy&#xff0c;自由度为2&#xff0c;模型收得最紧。所以只有所有图像都是用同一水平线或者同一已知倾斜角的摄…

图像拼接(二):OpenCV同时打开两个摄像头捕获视频

使用OpenCV实现同时打开两个USB摄像头&#xff0c;并实时显示视频。如果未检测有两个摄像头&#xff0c;程序会结束并发出“摄像头未安装好”的警告。这里推荐一个小巧的摄像头视频捕捉软件&#xff1a;amcap&#xff0c;使用它可以方便的检查每个摄像头是否能正常工作。 捕获…

elasticsearch的Linux下安装报错问题解决

1.启动报错如下: vim /etc/security/limits.conf 然后修改如下 * soft nofile 65536 * hard nofile 65536sudo vi /etc/pam.d/common-session 添加 session required pam_limits.so sudo vi /etc/pam.d/common-session-noninteractive 添加 session required pam_limits.so…

Fiddler抓包工具使用

先下载Fiddler 欢迎关注我的新微信公众号 ipgame&#xff0c;有什么问题可以提供交流的平台&#xff0c;欢迎大家讨论。 电脑最好是笔记本&#xff0c;这样能和手机保持统一局域网内&#xff1b;其他不多说&#xff0c;直接说步骤了。 一.对PC&#xff08;笔记本&#xff0…

Tensorboard--模型可视化工具

Tensorboard1.tensorboard in tensorflow1.1 tensorboard的启动过程1.2 tf.summary 可视化类型1.3 tf.summary 使用demo2.tensorboard in pytorch2.1 SummaryWriter 使用demo12.2 tSummaryWriter 使用demo22.3 tensorboard 数据再读取tensorboard in tensorflow &#xff1a;te…

opencv findContours 报错_acrt_first_block == header

报错_acrt_first_block header 之前一直使用OpenCV3.3VS2015 void AOIAlgorithm::findUnits(Mat& blkGray, vector<vector<cv::Point>> & blkContours) {Mat blkOBW;blur(blkGray, blkGray, cv::Size(5, 5));threshold(blkGray, blkOBW, 0, 255, CV_THR…

TensorFlow(2)-训练数据载入

tensorflow 训练数据载入1. tf.data.Dataset2. dataset 创建数据集的方式2.1 tf.data.Dataset.from_tensor_slices()2.2 tf.data.TextLineDataset()2.3 tf.data.FixedLengthRecordDataset()2.4 tf.data.TFRecordDataset()3. dateset 迭代操作iterator3.1 make_one_shot_iterato…

leetcode14. 最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1: 输入: ["flower","flow","flight"] 输出: "fl" 示例 2: 输入: ["dog","racecar",&quo…