`

一次遍历等概率选取字符串中的某个字符

 
阅读更多

http://blog.chinaunix.net/uid-7921481-id-3022614.html

存在一个等概率的0、1发生器。
给一个文本流,给定一个指定的字符'x',写一个函数,等概率地返回'x'的一个文本流偏移(就是'x'在字符串中的位置,比如文本为 axbx,那么x的偏移为{1, 3},最后你需要获得1或者3,概率分别为1/2
假设文本流每个字符1字节)


============================基本问题=========================================
-----------------------------------------------------------------------------
已知等概率的0-1生产器uint make0~1(),求等概率的0~n生产器uint make0~n(uint n)
uint make0~n(uint n)
{
//...
//make0~1();
//...
return ?; //
}
具体什么方法使得make0~n最高效还是大家去想吧。。。
这里高效的意思是很快就能够返回结果。

-----------------------------------------------------------------------------
=============================================================================

【方法一】
设共有N个字符.
for(;;)
{
产生0~N-1的随机数r
if(A[r]=='x') return r;
}

分析:因为0~N-1是等概率的,产生'x'的位置也是等概率的.
缺陷:循环return的概率是R/N (R为'x'的个数)
若N超级大R很小,for循环很难return.


【方法二】
1:vector<uint> a_pos;//从头到尾记录'x'出现的位置
2:这里有R==a_pos.size(). 产生0~R-1的随机数r
3:取a_pos[r]即可。

缺陷:当R很大时空间开销很大。
比方法一的优势在于: 这个无须循环一下就可return.


【方法三】
先遍历一遍字符串,记下有'x'出现的次数为R;
产生0~R-1 的随机数 r
再遍历一遍字符串获取第r个'x'的位置

缺陷:最坏情况要遍历两遍字符串
优势:克服了方法一和二的缺陷


=========面试官会问,还有没有更好的方法=========================
【方法四】
有没有只遍历一遍就OK的方法呢?
直观的,我们每碰到一个'x',设当前碰到的'x'的位置是i,我们可以以某个概率p去获取这个
'x'。此时获取'x'的概率绝对不是1/R,因为我们还不知道R的确切数字呢。
我们仍然需要继续遍历i之后的字符串,然后覆盖之。。。

于是列个方程组(*),获取第一个的概率是P(1),获取第i个的概率是P(i),获取第R个的概率是P(R)
满足:
P(1)(1-P(2))(1-P(3))...(1-P(R))=1/R
P(2)(1-P(3))...(1-P(R))=1/R
P(3)(1-P(4))...(1-P(R))=1/R
...
P(R-1)(1-P(R))=1/R
P(R)=1/R

上述方程组的思想是:每个字符获取的概率为1/R,遍历到它时能获取它,其后的所有该字符都不会获取。

求P(i),得:
P(R)=1/R
P(R-1)=1/(R-1)
P(R-2)=1/(R-2)
...
P(2)=1/2
P(1)=1

于是乎,碰到第一个'x'就取,碰到第二个就以1/2的概率去取(若概率发生,就更新当前的'x'的位置),
...第R个'x'就以1/R的概率去取,于是乎完成操作。

优势:遍历一遍
缺陷:每碰到一个指定的字符都需要产生相应的随机数(产生等概率的随机数的最高效的算法是什么呢?)

注意了:对于一个文本流,在该流没有流完之前,你不知道该流总共有多少个字符,你也不知道总共有多少个指定的字符,并且只流一次(不会再流一次),因此,方法一和方法三都不行不通。

 

http://www.cnblogs.com/DeadKnight/archive/2010/06/21/1762190.html

题:
给你一个字符串(可能有几亿个字符),给定一个特殊的字符'a',再给定一个可以产生0和1的随机数发生器,然后让你写一个函数,等概率地返回'a'的一个索引(就是'a'在字符串中的位置,比如字符串为 aaba,那么a的索引为{0, 1, 3},等概率地返回0、1或者3)

想:
最简单的想法:这个如果产生随机数,再把该随机数哈希到字符串长度范围内,再把得到的哈希值作为下标去看对应的字符满足不满足条件,满足条件则返回下标,不满足条件的话重新随机。缺点——如果满足条件的字符很少,那么完全不靠谱!
稍微容易想到的方法:遍历这个字符串,对满足条件的下标建立索引,然后根据索引大小产生随机数,随机访问索引,返回索引所对应的下标值。这个可以有,但是也有明显缺点——如果满足条件的字符很多,那么索引很大,占用大量存储!
最后就是完美的解答了:

答:

 

#include <sstream>
#include <iostream>
#include <string>
#include <time.h>

using namespace std;

int given_rand()
{
    return rand() % 2;
}

unsigned int my_rand()
{
    int i, result;
    for( i = 0, result = 0 ; i < 32 ; i++ )
    {
        result <<= 1;
        result += given_rand();
    }
    return result;
}

int main()
{    
    int index = 0, cnt = 0;
    stringstream strstring("aabbbaaabbbbabbbbabbbbbbbbbbbaabbbbbbb");
    int ret = 0;
    char c;

    srand(time(NULL));
    while (strstring >> c)
    {
        index++;
        if (c == 'a') {
            ++cnt;
            
            int rr = my_rand() % (cnt);            
            if (rr < 1)
                ret = index;
        }
        
    }
    cout << ret;
    return 0;
}
 
分享到:
评论

相关推荐

    LeetCode判断字符串是否循环-leetcode:leetcode

    两层遍历,先固定循环指标i,指标i遍历整个数组,再选取循环指标j,指标j从i+1遍历到数组最后,如果指标i和指标j所对应的数字相加为目标值target,则返回下标,否则继续遍历。 代码:two_sum.py 7. 题目描述 给出一个...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    varchar2 1~4000字节 可变长度字符串,与CHAR类型相比,使用VARCHAR2可以节省磁盘空间,但查询效率没有char类型高 数值类型 Number(m,n) m(1~38) n(-84~127) 可以存储正数、负数、零、定点数和精度为38位的浮点数...

    Python Cookbook

    1.8 检查字符串中是否包含某字符集合中的字符 15 1.9 简化字符串的translate方法的使用 18 1.10 过滤字符串中不属于指定集合的字符 20 1.11 检查一个字符串是文本还是二进制 23 1.12 控制大小写 25 1.13 访问子...

    AtemplateMeetinMiddle.cpp

    给你n个由大写字母组成的字符串, 从中选取尽量多的串使得选中的串中出现了的大写字母的出现次数都是偶数. 输出可以选的最大值和具体选的那些串 中途相遇法, 令奇数为1,偶数对应0 类似二分,本题中分为n1以及n2之后...

    delphi 开发经验技巧宝典源码

    0096 使用Pos函数返回子字符串第一次出现的索引值 66 0097 使用Quotedstr函数返回字符串的引证串 66 0098 使用Trim函数删除字符串的首尾空格 66 4.2 数学计算函数 67 0099 使用Abs函数返回指定数值的绝对值...

    delphi 开发经验技巧宝典源码06

    0096 使用Pos函数返回子字符串第一次出现的索引值 66 0097 使用Quotedstr函数返回字符串的引证串 66 0098 使用Trim函数删除字符串的首尾空格 66 4.2 数学计算函数 67 0099 使用Abs函数返回指定数值的绝对值...

    机器学习+决策树+python实现对率回归决策树

    对于给定西瓜数据集3.0,将字符串类型的属性取值转换为数值类型以便模型进行训练,并将连续属性离散化以便选取划分点,通过正确率来选取根节点,最终得到决策树数组。通过dealanddraw(n0, pngname)函数将数组转化为...

    《程序天下:JavaScript实例自学手册》光盘源码

    3.11 判断字符串中有多少汉字 3.12 去除字符串的前后空格 3.13 刷新时清空所有文本框 3.14 随意改变大小的文本框 3.15 文本框的自动全选 3.16 文本框滚动导航 3.17 按钮获取焦点 3.18 文本框获取焦点弹出下拉框 3.19...

    程序天下:JavaScript实例自学手册

    3.11 判断字符串中有多少汉字 3.12 去除字符串的前后空格 3.13 刷新时清空所有文本框 3.14 随意改变大小的文本框 3.15 文本框的自动全选 3.16 文本框滚动导航 3.17 按钮获取焦点 3.18 文本框获取焦点弹出下拉框 3.19...

    Golang2-new.docx

    3.3.5. 字符串的 for range 循环 40 3.3.6. 用字节切片构造字符串 41 3.3.7. 用rune切片构造字符串 42 3.3.8. 字符串的长度 42 3.3.9. 字符串是不可变的 42 3.3.10. UTF8(go圣经) 43 3.4. 常量 45 3.4.1. ...

    leetcode:参考@CyC2018的leetcode题解。Java工程师LeetCode刷题必备。主要根据LeetCode的tag进行模块划分,每部分都选取了比较经典的题目,题目以medium和easy为主,少量hard题目

    字符串编辑 其它问题 数学 素数 最大公约数 进制转换 阶乘 字符串加法减法 相遇问题 多数投票问题 其它 数据结构相关 栈和队列 哈希表 字符串 数组与矩阵 1-n 分布 有序矩阵 链表 树 递归 层次遍历 前中后序遍历 BST...

    基于C++实现的改进版遗传算法解决TSP问题源码+项目说明.zip

    - 使用一个不重复的,首尾相同的字符串来表示一个解,该字符串即TSP的顺序 - 使用交叉,变异两种方式产生新的解,并根据数据来计算解的适应度 - 种群定义为当前所有解的一个集合,当种群中的每个个体完成一次“进化...

    jQuery详细教程

    您也许已经注意到在我们的实例中的所有 jQuery 函数位于一个 document ready 函数中: $(document).ready(function(){ --- jQuery functions go here ---- }); 这是为了防止文档在完全加载(就绪)之前运行 jQuery...

    php网络开发完全手册

    7.3.1 字符串重复操作——str_repeat 104 7.3.2 字符串替换操作——str_replace 7.3.2 和str_ireplace 104 7.3.3 字符串分解操作——str_split 106 7.3.4 字符串单词数的计算函数—— 7.3.4 str_word_count 107 ...

    数据结构(C++)有关练习题

    B. 球最大值函数max:通过单链表的一趟遍历,在单链表中确定值最大的结点; C. 统计函数number:统计单链表中具有给定值x的所有元素数量; D. *建立函数create:根据一维数组a[n]建立一个单链表,使...

    超实用的jQuery代码段

    11.19 如何构建最优化的字符串 11.20 使用jQuery产生GUID值 11.21 使用jQuery实现聚合函数 11.22 用jQuery打印网页的特定区域 11.23 禁止表单被提交 11.24 使用delay()延迟执行动画 11.25 在网页上运行本地程序的...

    JavaScript权威指南(第六版) 清晰-完整

    7.12 作为数组的字符串 第8章 函数 8.1 函数定义 8.2 函数调用 8.3 函数的实参和形参 8.4 作为值的函数 8.5 作为命名空间的函数 8.6 闭包 8.7 函数属性、方法和构造函数 8.8 函数式编程 第9章 类和模块 9.1 类和原型...

    基于C++开发的射击游戏

    // 读取完后m_sEnimyName中的字符串是每个section name的连接,两两之间用”\0”字符分开,如: // “enimy01.enimy02.enimy03”其中的点就是空字符 GetPrivateProfileSectionNames(m_sEnimyName, sizeof(m_...

Global site tag (gtag.js) - Google Analytics