活动规则实现算法小思
最近有一个开发需求 (签到活动的变种)
需求:用户需要连续的在页面上面签到,签到成功一次则增加一个积分,如果中途有一天没有签到则扣除一个积分.账户不能为负数,账户每次都从不小于零开始计算
问题:想怎么最简单的方法来实现这个功能,最好能在一个表达式解决问题,
然后就得到三个实现方式,
前两个是常规的实现方式
第三个比较特殊的实现方式 一个表达式可以实现功能(达到目标),
用到主要知识点:
1:递归正则表达式.
2:实现算法这边可以理解为<> () 这种的成对抵消, 1 表示< ;0表示>, 10为0,则递归替换(递归正则表达式)所有的成对的10,不成对的最后剩下的肯定是后面是1前面是0.(反过来替换01 则剩下的肯定是前面是1后面就是0). 根据这个特性最后留下0{n}1{m}这样的字符串,那么m的个数(1字符串长度)就是积分数量.
不喜欢多说 直接上代码吧
签到用1 没有签到用0填充 开始生成一些随机用户随机当期内的随机签到,用数组存储,
如果用第三种方法,用单个字段字符串存(1010111)储单个用户签到,否则需要在处理成字符串.
//玩法, 签到的变种 用户需要连续的在页面上面签到,签到成功一次则增加一个积分,
//如果中途有一天没有签到则扣除一个积分.账户不能为负数,账户每次都从不小于零开始计算
//假如我们有若干个用户 randUserNum,当前活动周期为 randDayNum 我们先生成一些用户数据和情况
$randUserNum = rand(5,10);
$randDayNum = rand(1,6);
$users = [];
$sersAccount = []; //整理后的用户账户体系
for($i=0;$i<$randUserNum;$i++){
$user = [];
for($j=0;$j<$randDayNum;$j++){
$user[] = rand(0,1);
}
$users[] = $sersAccount[] = $user;
unset($user);
}
//第一种方法 循环去处理
foreach ($users as $key=>$user){
$point = 0; //每个账户都是零
for($i = 0; $i < $randDayNum; $i++){
if($user[$i]){ //如果当前签到了 增加积分
$point += 1;
}elseif($point){//如果需要减分 当前账户必须为有积分 就是说活动期间的结算结果都不能负分
$point -= 1;
}
}
$sersAccount[$key]['way_one'] = $point;// 这个算法算出来的积分
}
//第二种方法 递归
foreach ($users as $key=>$user){
$sersAccount[$key]['way_two'] = getPoint($user,0); //初始账户为0
}
//递归获得累加用户积分
function getPoint($usersigns,$point){
$sign = array_shift($usersigns); //每次取出一个元素
if( $sign !== NULL){ //当最后一个元素的时候终止递归
if($sign){ //如果当前签到了 增加积分
$point +=1;
}elseif($point){//如果需要减分 当前账户必须为有积分 就是说活动期间的结算结果都不能负分
$point -=1;
}
return getPoint($usersigns, $point);
} else {
return $point;
}
}
//第三种方法 特殊方法 原理 根据当前的规则可以推算出来10其实就是0积分 把所有的10清空 那么 剩下的 1的个数就是积分,
//假如 010101010101 就是 替换掉所有的10 就是 01 就是1积分1001100 递归替换掉10 就是0
//当然还有一些其他的字符串处理规则 例如 如果 知道天数不太大 可以直接转换成整形 来处理 就不用str_replace
foreach ($users as $key=>$user){
$user_str = implode('', $user); //这一步可以在存储的时候就用字符串存储
//(?R) 这个为正则的递归匹配当前的表达式 类似 <a<b>c<dddeee<asdf>>>
$user_str = str_replace('0', '', preg_replace('/1(?R)*0/', '', $user_str));
$sersAccount[$key]['way_three'] = strlen($user_str); //只剩下1111 这样子 有多少个 1 就是多少积分
}
file_put_contents('data2.php', var_export($sersAccount,true)); //结果保存下 查看
结果测试
array (
0 =>
array (
0 => 0,
1 => 1,
2 => 1,
3 => 1,
4 => 1,
'way_one' => 4,
'way_two' => 4,
'way_three' => 4,
),
1 =>
array (
0 => 0,
1 => 0,
2 => 0,
3 => 0,
4 => 1,
'way_one' => 1,
'way_two' => 1,
'way_three' => 1,
),
2 =>
array (
0 => 0,
1 => 0,
2 => 1,
3 => 1,
4 => 1,
'way_one' => 3,
'way_two' => 3,
'way_three' => 3,
),
3 =>
array (
0 => 0,
1 => 1,
2 => 0,
3 => 1,
4 => 0,
'way_one' => 0,
'way_two' => 0,
'way_three' => 0,
),
4 =>
array (
0 => 1,
1 => 1,
2 => 1,
3 => 1,
4 => 0,
'way_one' => 3,
'way_two' => 3,
'way_three' => 3,
),
5 =>
array (
0 => 1,
1 => 1,
2 => 0,
3 => 1,
4 => 0,
'way_one' => 1,
'way_two' => 1,
'way_three' => 1,
),
6 =>
array (
0 => 1,
1 => 1,
2 => 0,
3 => 0,
4 => 0,
'way_one' => 0,
'way_two' => 0,
'way_three' => 0,
),
7 =>
array (
0 => 1,
1 => 0,
2 => 0,
3 => 0,
4 => 1,
'way_one' => 1,
'way_two' => 1,
'way_three' => 1,
),
)
