笔试算法题(26):顺时针打印矩阵 & 求数组中数对差的最大值

出题: 输入一个数字矩阵,要求从外向里顺时针打印每一个数字;

分析:

  • 从外向里打印矩阵有多重方法实现,但最重要的是构建合适的状态机,这样才能控制多重不同的操作;

  • 注意有四种打印模式(左右,上下,右左,下上),所以需要一个index变量控制每次循环时执行的打印模式;

  • 注意水平打印和垂直打印分别需要两个变量控制打印元素,并且两组变量中的两个端点都是相互靠近的(hs和he,vs和he),每执行一种打印模式之前,需要更新当前打印模式中打印方向的其实坐标,因为它已经在上一种打印模式中打印过;

  • 每一种打印模式执行之前需要检测hs>he或者vs>ve,如果成立则打印结束;

  • 其他方法:递归法:每次都打印矩阵第一行,然后将剩余的元素逆时针旋转90度创建一个矩阵;贪吃蛇法:创建一个bool矩阵表示元素是否被打印,然后创建一个类似index的控制打印模式的变量,遇到false的元素就转到下一个打印模式;

解题:


 1 /**
2 * 设置四个变量,两两一组分别表示水平和垂直方向的打印的起始点
3 * index表示四种打印方式中的一种(左右,上下,右左,下上)
4 * 当两两一组的变量中hs>he或者vs>ve的时候结束打印
5 * 注意每一种打印模式开始之前,需要更新起始点的坐标,因为
6 * 它已经在上一个打印模式中打印过
7 * */
8 void clockwisePrintMatrix(int *array, int x, int y) {
9 int hs=-1, he=x-1;
10 int vs=0, ve=y-1;
11 int index=4;
12
13 while(true) {
14 printf("hs=%d, he=%d, vs=%d, ve=%d\n",hs,he,vs,ve);
15 index%=4;
16 if(index==0) {
17 /**
18 * 左右打印模式:
19 *
20 * */
21 hs++;
22 if(hs>he) break;
23 for(int i=hs;i<=he;i++)
24 printf("%d, ",array[vs*x + i]);
25 printf("\n");
26 } else if(index==1) {
27 /**
28 * 上下打印模式:
29 *
30 * */
31 vs++;
32 if(vs>ve) break;
33 for(int i=vs;i<=ve;i++)
34 printf("%d, ",array[i*y + he]);
35 printf("\n");
36 } else if(index==2) {
37 /**
38 * 右左打印模式:
39 *
40 * */
41 he--;
42 if(hs>he) break;
43 for(int i=he;i>=hs;i--)
44 printf("%d, ",array[ve*x + i]);
45 printf("\n");
46 } else if(index==3) {
47 /**
48 * 下上打印模式:
49 *
50 * */
51 ve--;
52 if(vs>ve) break;
53 for(int i=ve;i>=vs;i--)
54 printf("%d, ",array[i*y + hs]);
55 printf("\n");
56 }
57 index++;
58 }
59 }
60
61 int main() {
62 int matrix[]={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};
63 clockwisePrintMatrix(matrix, 5, 5);
64 return 0;
65 }

出题:一个数组中,某一个数字减去它右边数字得到一个数对差,求所有数对差中的最大值;

分析:

  • 数对差的解法可转换成求最大子数组和,或者转换成DP问题;

  • 解法1:构建子数组最大和值
    定义数
    组:array[i]-array[i+1];array[i+1]-array[i+2];……;array[j-1]-array[j];所以
    array[i]-array[j]的差就是前面所有相邻元素差的和,所以将原始数组转换成相邻元素的差组成的数组,而求原数组元素差的最大值转换成新数
    组的子数组元素的最大和;

  • 解法2:动态规划解法:diff[i]存储array[i]与其左边数组最大元素的差值,得到diff[i]之后求diff[i+1],则需要知道
    array[i+1]左边数组的最大元素,而有两种可能,计算diff[i]的时候得到的最大值,或者就是array[i]。所以只需一遍扫描就可以;

解题:


 1 int MaxDif(int *array, int length) {
2 /**
3 * 定义局部stack数组存储相邻元素差值
4 * 循环获取相邻元素差值
5 * */
6 int difarray[length-1];
7 for(int i=0;i<length-1;i++) {
8 difarray[i]=array[i]-array[i+1];
9 printf("\n%d",difarray[i]);
10 }
11 /**
12 * sum记录最大和值
13 * tempsum记录当前元素的和值
14 * 如果元素为+++++++,则从开始相加到最后
15 * 如果元素为-------,则sum保持为0
16 * 如果元素为++++---,则sum保持为前半正数
17 * 如果元素为----+++,则sum保持为后半正数
18 * 还有其他满足条件的情况
19 * */
20 int tempsum=0, sum=0;
21 for(int i=0;i<length-1;i++) {
22 tempsum+=difarray[i];
23 if(tempsum<0)
24 tempsum=0;
25 else if(tempsum>sum)
26 sum=tempsum;
27 }
28
29 return sum;
30 }
31
32 int MaxDifDP(int *array, int length) {
33 /**
34 * difarray[i]用于存储array[i]左边的最大元素
35 * 与array[i]的差值,
36 * difarray[i+1]同理,但根据DP原理,左边的最大
37 * 元素可能是array[i]找到的最大元素,可能是
38 * array[i]本身,所以一遍扫描,DP复用
39 * */
40 int difarray[length-1];
41 int max=array[0];
42 for(int i=0;i<length-1;i++) {
43 if(array[i]>max)
44 max=array[i];
45 difarray[i]=max-array[i+1];
46 }
47 int difmax=difarray[0];
48 for(int i=1;i<length-1;i++) {
49 if(difarray[i]>difmax)
50 difmax=difarray[i];
51 }
52 return difmax;
53 }
54
55 int main() {
56 int array[]={6,7,9,6,-4,0,7,9};
57 printf("\nthe max diff is: %d",MaxDif(array,8));
58 printf("\nthe max diff is: %d",MaxDifDP(array,8));
59 return 0;
60 }

时间: 2024-11-17 03:28:48

笔试算法题(26):顺时针打印矩阵 & 求数组中数对差的最大值的相关文章

【笔试】37、顺时针打印矩阵

/**************************************************************************************** *题目:顺时针打印矩阵 * 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字.例如:如果输入如下矩阵 * 1 2 3 4 * 5 6 7 8 * 9 10 11 12 * 13 14 15 16 * 依次打印:1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 *时间:2015年8

《github一天一道算法题》:分治法求数组最大连续子序列和

看书.思考.写代码! /*************************************** * [email protected] * blog: http://blog.csdn.net/hustyangju * 题目:分治法求数组最大连续子序列和 * 思路:分解成子问题+合并答案 * 时间复杂度:O(n lgn) * 空间复杂度:O(1) ***************************************/ #include <iostream> using nam

算法题:蛇形打印矩阵

1 // Snake.cpp : print matric(n*n). 2 //////////// n=3: 3 // 1 2 6 4 // 3 5 7 5 // 4 8 9 6 //////////// n=4: 7 // 1 2 6 7 8 // 3 5 8 13 9 // 4 9 12 14 10 // 10 11 15 16 11 12 #include "stdafx.h" 13 #include "vector" 14 #include "d

笔试算法题(20):寻找丑数 &amp; 打印1到N位的所有的数

出题:将只包含2,3,5的因子的数称为丑数(Ugly Number),要求找到前面1500个丑数: 分析: 解法1:依次判断从1开始的每一个整数,2,3,5是因子则整数必须可以被他们其中的一个整除,如果不包含任何其他因子则最终的结果为1: 解法2:小丑数必然是某个大丑数的因子,也就是乘以2,3,或者5之后的值,所以可以利用已经找到的丑数来寻找下一个丑数,使用数组有序保存已经找到的丑 数,并且当前最大丑数值为M:用大于M/2的丑数乘以2得到M1,用大于M/3的丑数乘以3得到M2,用大于M/5的丑数

笔试算法题(22):二分法求旋转数组最小值 &amp; 骰子值概率

出题:将一个数组最开始的k个(K小于数组大小N)元素照搬到数组末尾,我们称之为数组的旋转:现在有一个已经排序的数组的一个旋转,要求输出旋转数组中的最小元素,且时间复杂度小于O(N): 分析: 时间复杂度小于O(N)也就是不能用常规的遍历思路:可以将数组看成两个都是递增序列(假设为升序)的子数组,并且前半段的元素均大于等于后半段的元素,分界点的位于后半段数组的第一个元素就是最小元素: 具体算法:两个指针left和right指向数组第一个和最后一个元素,使用Binary Search确定中间元素mi

笔试算法题(06):最大连续子数组和 &amp; 二叉树路径和值

出题:预先输入一个整型数组,数组中有正数也有负数:数组中连续一个或者多个整数组成一个子数组,每个子数组有一个和:求所有子数组中和的最大值,要求时间复杂度O(n): 分析: 时间复杂度为线性表明只允许一遍扫描,当然如果最终的最大值为0表明所有元素都是负数,可以用线性时间O(N)查找最大的元素.具体算法策略请见代码和注释: 子数组的起始元素肯定是非负数,如果添加的元素为正数则记录最大和值并且继续添加:如果添加的元素为负数,则判断新的和是否大于0,如果小于0则以下一个元素作为起始元素重新开始,如果大于

笔试算法题(43):布隆过滤器(Bloom Filter)

议题:布隆过滤器(Bloom Filter) 分析: BF由一个很长的二进制向量和一系列随机映射的函数组成,通过多个Hash函数将一个元素映射到一个Bit Array中的多个点,查询的时候仅当所有的映射点都为1才能判断元素存在于集合内:BF用于检索一个元素是否在一个集合中,记忆集合求交集:优点是空间 和时间效率都超过一般查询算法,缺点是有一定的误判概率和删除困难: 如下图,使用三个哈希函数对每个元素进行映射,这样每个元素对应HashTable中的三个位置,如果查找w是否在HashTable中则仍

笔试算法题(11):Josephus环 &amp; Fibonacci序列

出题:Josephus Cycle,约瑟夫环问题.k个数字连成一个环,第一个数字为1.首先从1开始计数删除第m个数字:然后从上次被删除的数字的下一个数字开始计数,删除第m个数字:重复进行第二步直到只剩下一个数字:输出最后剩下的一个数字: 分析: 解法1:考虑到问题的特殊性,可以使用哑元素表示删除的元素从而避免由于删除元素带来的额外操作,所以链表实现的话不用考虑删除操作,数组实现的话不用考虑内存移动操作.当然完全可以不适用哑元素,对于链表而言可以节省查找时间,数组的话需要增加数组元素的平移开销:

笔试算法题(38):并查集(Union-Find Sets)

出题:并查集(Union-Find Sets) 分析: 一种树型数据结构,用于处理不相交集合(Disjoint Sets)的合并以及查询:一开始让所有元素独立成树,也就是只有根节点的树:然后根据需要将关联的元素(树)进行合并:合并的方式仅仅是将一棵树最原始的节点的父亲索引指向另一棵树: 优化:加入一个rank数组存储节点深度的下界(从当前节点到其最远子节点的距离),从而可以启发式的对树进行合并,从而减少树的深度,防止树的退化:使 得包含较少节点的树根指向包含较多节点的树根,具体指代为树的高度:另