2.4 算法和数据操作
-
排序和查找是重点,重点掌握二分查找,归并排序,快速排序。
-
递归和循环两种方式看要求,或和面试官讨论。
-
查找有顺序查找、二分查找、哈希表查找、二叉排序树查找等。需随时能够完整正确写出二分查找的算法。
-
排序有插入排序、冒泡排序、归并排序、快速排序等,需要比较其之间的优劣、特点。随时能够完整正确写出快速排序的算法。
-
快速排序
分治法排序的一种算法,即把大问题化为小问题。算法思路是选取一个基准,把比他大的放在他右边,小的放左边,再对左右分别进行同样方法的排序。
网上常规的方法是每次以第一个数为基准,如下图。class L_QuickSort{ private: static int partition(int input[], int left, int right) { if (input == nullptr || left > right || left < 0 || right < 0) throw new std::exception("Invalid Input/n"); //取第一个为基准 int base = input[left]; while (left < right) { while (left < right && input[right] >= base) right--; input[left] = input[right]; while (left < right && input[left] <= base) left++; input[right] = input[left]; } input[left] = base; return left; } public: static void quickSort(int inputArr[], int start, int end) { if (inputArr == nullptr || start > end || start < 0 || end < 0) throw new std::exception("Invalid Input/n"); int div = partition(inputArr, start, end); if (div - start > 1) quickSort(inputArr, start, div - 1); if (end - div > 1) quickSort(inputArr, div + 1, end); } };
剑指上的做法则更还原本算法的精髓,最开始的基准是随机取的,然后将以这个数字将数组分为大于和小于的两部分,在对这两部分继续递归。
重点在于分块partition函数的算法static int patition(int data[], int start, int end) { if (data == nullptr || start > end || start < 0 || end < 0) throw new std::exception("Invalid Input/n"); //随机选一个start-end范围内的数字作为基准 int index = (rand() % (end - start + 1)) + start; //将这个数字先放到最后,对前面的数字进行分块 mySwap(&data[index], &data[end]); //small代表比标准小的最后一个数字,即小的与大的之间的分界 int small = start - 1; //从头到尾循环,将比标准大的数字放在后面,小的放在前面,small表示其交界处的位置 for (index = start; index < end; ++index){ if (data[index] < data[end]){ ++small; if (index != small) mySwap(&data[index], &data[small]); } } //最后把标准与small+1,即第一个比标准大的数字交换,完成前面都是小的,后面都是大的 mySwap(&data[small+1], &data[end]); return small + 1; } //排序主函数与上面类似。
-
二分查找算法的应用,实际问题能想到。
-
一般情况下使用递归代码更简单,但开销也会大,时间效率低,还有可能出现栈溢出的错误,要看情况使用。
-
斐波那契数列:
表达式为: F(n) = F(n-1) + F(n-2), F(0)=0, F(1)=1.
可以使用递归和非递归,如果数字很大,建议使用非递归循环算法(从小到大开始加)。 -
斐波那契数列的应用
例如:
有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?
例如:
都可以以斐波那契数列数列来解决。 -
位运算:
与&、或|、取反~、异或^,左移、右移。
左移右边补0,左边丢弃。右移复杂一些,右移右边丢弃,左边补符号,如果正数则补0,负数补1。 -
位运算应用:二进制数中1的个数。
常规算法1:
取这个数左移,统计最低位的1的个数,直到变成0。但负数时会遇到问题。
常规2:
取一个i=1,把这个数右移,统计1的个数,但 效率比较低,因为32位的int则要移32次。
变通算法:
发现将一个数减1再与自己相位与,则会把最右边的1变成0。比如1001&1000=1000;1100&1011=1000。
这样,只要做这个操作直到变成0,统计次数即可。
一些二进制的题可能会用到统计1的个数来解决,此时要想到此算法。 -
要注意边界条件。