Redis和Memcache有什么区别?
答案
共同点:
- 都是内存数据库。
- 都可以做一主多从的分布式集群。
区别:
- Redis支持hash、list、set、sorted set等多种数据,Memcache 仅支持字符串键值数据。
- Redis 只使用单核;Memcache可使用多核多线程。所以100K以下数据Redis性能好,以上Memcache性能好。
- Redis 数据可以持久化到磁盘;Memcache 不支持数据持久化,关闭后数据随之消失。
- Redis 单个key(变量)存放的数据有1GB的限制;Memcache 单个key(变量)存放的数据有1M的限制。
- Redis 利用单线程模型提供了事务的功能;Memcached提供了cas命令来保证数据一致性。
- redis 支持master-slave复制模式做分布式;memcache可以使用magent的一致性hash做分布式。
CAS(Check and Set)是一个确保并发一致性的机制,属于“乐观锁”范畴; CAS原理很简单:拿版本号,操作,对比版本号,如果一致就操作,不一致就放弃任何操作
PHP求一个数组中出现最多的值
答案
1
2
3
4
5
6
7
8
9
function getMaxCountValue($array)
{
$array2 = array_count_values($array); // 统计数组中所有值出现的次数
arsort($array2); // 按照键值对关联数组进行降序排序
$first = reset($array2);
$firstKey = key($array2);
return [$firstKey, $first];
}
测试代码:
1
2
3
4
$array = array(1, 1, 1, 54, 3, 4, 3, 4, 3, 14, 3, 4, 3, 7, 8, 9, 12, 45, 66, 5, 7, 8, 9, 2, 45, 3);
list($key, $count) = getMaxCountValue($array);
echo "数组中数字{$key}重复次数最多,为:{$count}次";
输出结果:
数组中数字3重复次数最多,为:6次
从数组中查找最小的k个元素PHP版
答案
思路:
- 假设最前面的
1000
个数为最小的,算出这1000
个数中最大的数,然后和第1001
个数比较 - 如果这个最大的数比第
1001
个数小的话,跳过 - 如果这个最大的数比第
1001
个数大则将两个数交换位置,并算出新的1000
个数里面的最大数 - 再和下一个数比较,以此类推
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 从数组里找出最小的 $k 个数
* @param $arr array 输入数组
* @param $k int 输出元素个数
* @return array 最小元素集合
*/
function getMinK($arr, $k)
{
$n = count($arr);
$minArray = array();
for ($i = 0; $i < $n; $i++) {
if ($i < $k) {
$minArray[$i] = $arr[$i];
} else {
if ($i == $k) {
$maxPos = getMaxPos($minArray);
$max = $minArray[$maxPos];
}
if ($arr[$i] < $max) {
$minArray[$maxPos] = $arr[$i];
$maxPos = getMaxPos($minArray);
$max = $minArray[$maxPos];
}
}
}
return $minArray;
}
/**
* 从数组中查找最大值的位置
* @param $arr array 待查找数组
* @return int 位置
*/
function getMaxPos($arr)
{
$pos = 0;
for ($i = 1; $i < count($arr); $i++) {
if ($arr[$i] > $arr[$pos]) {
$pos = $i;
}
}
return $pos;
}
测试代码:
1
2
3
4
5
$arr = [1, 100, 20, 22, 33, 44, 55, 66, 23, 79, 18, 20, 11, 9, 129, 399, 145, 2469, 58];
$res = getMinK($arr, 5);
// 输出:[1,9,20,11,18]
echo json_encode($res);
二分查找PHP版
答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function binarySearch($array, $search)
{
$low = 0;
$high = count($array) - 1;
if ($search < $array[$low] || $search > $array[$high]) {
return false;
}
while ($low <= $high) {
$mid = floor(($high + $low) / 2);
if ($array[$mid] > $search) {
$high = $mid - 1;
} else if ($array[$mid] < $search) {
$low = $mid + 1;
} else {
return $mid;
}
}
return false;
}
时间复杂度:O(logn)
约瑟夫环问题PHP版
一群猴子排成一圈,按1,2,…,n依次编号。
然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王。
要求编程模拟此过程,输入m、n, 输出最后那个大王的编号。
答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* 方法一
*/
function monkeyKing($n, $m)
{
$arr = range(1, $n); //构造一个数组
$i = 1; //从第一个开始循环
while (count($arr) > 1) { //如果总数大于1
if ($i % $m != 0) {
$arr[] = $arr[$i - 1]; //不被踢出则压入数组尾部
}
unset($arr[$i - 1]); //压入数组然后删除
$i++; //继续循环
}
return $arr[$i - 1]; //直至最后剩下一个为大王
}
/**
* 方法二
*/
function getMonkeyKing2($n, $m)
{
$r = 0;
for ($i = 2; $i <= $n; $i++) {
$r = ($r + $m) % $i;
}
return $r + 1;
}
答案解析
下面是方法1的模拟过程,对于不剔除的猴子,不断的加入数组尾部:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$n = 5
$m = 3
$arr = [1, 2, 3, 4, 5]
$i $arr
---+------------------------
1 x 2 3 4 5 1
2 x x 3 4 5 1 2
>3 x x x 4 5 1 2
4 x x x x 5 1 2 4
5 x x x x x 1 2 4 5
>6 x x x x x x 2 4 5
7 x x x x x x x 4 5 2
8 x x x x x x x x 5 2 4
>9 x x x x x x x x x 2 4
10 x x x x x x x x x x 4 2
11 x x x x x x x x x x x 2 4
>12 x x x x x x x x x x x x 4
约瑟夫问题来历:
这个问题是以弗拉维奥·约瑟夫命名的,它是1世纪的一名犹太历史学家。他在自己的日记中写道,他和他的40个战友被罗马军队包围在洞中。他们讨论是自杀还是被俘,最终决定自杀,并以抽签的方式决定谁杀掉谁。约瑟夫斯和另外一个人是最后两个留下的人。约瑟夫斯说服了那个人,他们将向罗马军队投降,不再自杀。约瑟夫斯把他的存活归因于运气或天意,他不知道是哪一个。
如何设计/优化一个访问量比较大的网站?
答案
- 减少HTTP 请求(比如使用雪碧图)
- 优化数据库(范式、SQL语句、索引、配置、读写分离)
- 缓存使用(Memcache、Redis)
- 负载均衡
- 动态内容静态化+CDN
- 禁止外部盗链(refer、图片添加水印)
- 控制大文件下载
- 使用集群
-
PHP接口和抽象类有什么区别?
答案
相同点:
- 都是抽象类,都不能实例化。
interface
实现类及abstract class
的子类都必须要实现已经声明的抽象方法。
区别:
- 定义接口用
interface
关键词;定义抽象类用abstract class
。 - 接口需要实现,要用
implements
;抽象类需要继承,要用extends
。 - 接口中的每一个方法都是抽象方法,都只是声明的,没有方法体,实现类必须要实现。而抽象类的子类可以有选择地实现。
- 接口没有数据成员;抽象类可以有数据成员,实现数据的封装。
- 接口没有构造函数;抽象类可以有构造函数。
- 接口的方法都是
public
类型,而抽象类中的抽象方法可以是protected
或public
,但不能为private
。 - 一个类可以同时实现多个接口,但是只能继承一个抽象类。
答案解析
抽象类中的子类可以有选择地实现抽象类,有两点含义:
- 抽象类中并非所有的方法都是抽象的,只有那些冠有
abstract
的方法才是抽象的,子类必须实现。那些没有abstract
的方法,在abstract class
中必须定义方法体; - 抽象类的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
抽象类是interface
与class
的中介,抽象类在接口和class
中起到了承上启下的作用。
- 一方面,
abstract class
是抽象的,可以声明抽象方法,以规范子类必须实现的功能; - 另一方面,它又可以定义缺省的方法体,供子类直接使用或覆盖;
- 另外,它还可以定义自己的实例变量,以供子类通过继承来使用。
接口中的抽象方法前不用也不能加abstract
关键字,默认隐式就是抽象方法,也不能加final
关键字来防止抽象方法的继承。而抽象类中抽象方法前则必须加上abstract
表示显示声明为抽象方法。
MySQL如何高效率随机获取N条数据?
答案
假设表叫做mm_account
。
ID连续的情况下(注意不能带where
,否则结果不好):
1
2
3
4
5
SELECT *
FROM `mm_account` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `mm_account`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id ASC LIMIT 4;
ID不连续的情况下:
1
2
3
4
SELECT * FROM `mm_account`
WHERE id >= (SELECT floor(RAND() * (SELECT MAX(id) FROM `mm_account`))) and city="city_91" and showSex=1
ORDER BY id LIMIT 4;
如果有一个字段叫id,最快的方法如下(随机获取5条):
1
2
3
4
SELECT * FROM mm_account
WHERE id >= ((SELECT MAX(id) FROM mm_account)-(SELECT MIN(id) FROM mm_account)) * RAND() + (SELECT MIN(id) FROM mm_account)
limit 5;
如果带where
语句,上面就不适合了,带where
语句请看下面:
1
2
3
4
5
SELECT *
FROM `mm_account` AS t1 JOIN (SELECT ROUND(RAND() * (
(SELECT MAX(id) FROM `mm_account` where id<1000 )-(SELECT MIN(id) FROM `mm_account` where id<1000 ))+(SELECT MIN(id) FROM `mm_account` where id<1000 )) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 5;