数据结构---数组(2)

1.顺时针打印矩阵(剑指offer-20)

题目:给定一个矩阵,从外向内顺时针打印矩阵中的每一个数字。
例如:给定矩阵:
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}

解析:

1.循环条件怎么判定?一个矩阵,给定起点(startX,startY)和终点(endX,endY)(即位于对角线上的两个点)就可以打印一周,然后向里进一周(即++startX,++startY,--endX,--endY)即可,如果起始点坐标<终止点坐标(即startX<endX或者startY<endY)循环结束。
2.给定起点和终点,打印一周的结束条件是什么?我画了三种情况的矩阵4×4矩阵,3×5矩阵,5×3矩阵(所有矩阵无非就这三种类型,正方形的,偏“胖”的,偏“瘦”的),很快发现,只有三种情况:一直循环到结束,只剩下一行,只剩下一列。所以我们的函数首先判定:只有一行?打印该行;只有一列,打印该列。都不是,打印四条边上的数字。

	// 给定矩阵,给定行列,由外向内顺时针打印数字
	public static void PrintMatrixClockwisely(int[][] matrix, int rows,
			int columns) {
		if (matrix == null || rows < 0 || columns < 0)
			return;

		int startX = 0;
		int startY = 0;
		int endX = rows - 1;
		int endY = columns - 1;
		while (true) {
			if (startX > endX && startY > endY)
				break;
			if (startX == endX && startY > endY)
				break;
			if (startX > endX && startY == endY)
				break;

			PrintMatrixCircle(matrix, startX, startY, endX, endY);

			++startX;
			++startY;
			--endX;
			--endY;
		}
	}

	// 对于给定矩阵,给定对角线上两点,打印这一周的元素
	public static void PrintMatrixCircle(int[][] num, int sX, int sY, int eX,
			int eY) {
		// 只有一行的情况,直接打印,返回。
		if (sX == eX) {
			for (int j = sY; j <= eY; ++j) {
				System.out.print(num[sX][j] + " ");
			}

			return;
		}
		// 只有一列的情况,直接打印,返回。
		if (sY == eY) {
			for (int i = sX; i <= eX; ++i) {
				System.out.print(num[i][sY] + " ");
			}
			return;
		}

		// 上行
		for (int p = sY; p < eY; ++p) {
			System.out.print(num[sX][p] + " ");
		}
		// 右列
		for (int q = sX; q < eX; ++q) {
			System.out.print(num[q][eY] + " ");
		}
		// 下行
		for (int m = eY; m > sY; --m) {
			System.out.print(num[eX][m] + " ");
		}
		// 左列
		for (int n = eX; n > sX; --n) {
			System.out.print(num[n][sY]+ " ");
		}

	}


2、数组中出现次数超过一半的数字(剑指offer-29)
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

解法一:
如果一个数字在数组中出现的次数超过了数组长度的一半,那么对这个数组进行排序,位于数组中间位置的那个数就是出现次数超过一半的那个数。对数组排序的时间复杂度是O(nlog(n)),但是对于这道题目,还有更好的算法,能够在时间复杂度O(n)内求出。我们写过快速排序算法,其中的Partition()方法是一个最重要的方法,该方法返回一个index,能够保证index位置的数是已排序完成的,在index左边的数都比index所在的数小,在index右边的数都比index所在的数大。那么本题就可以利用这样的思路来解。
通过Partition()返回index,如果index==mid,那么就表明找到了数组的中位数;如果index<mid,表明中位数在[index+1,end]之间;如果index>mid,表明中位数在[start,index-1]之间。知道最后求得index==mid循环结束。
根据求得的index,遍历一遍数组,每当出现一个等于index所指向的数时time++,最后判断time是否大于数组长度的一半,如果大于则表明index所指向的数就是所求的数,如果不是,则表明不存在一个数出现的次数超过数组长度的一半。

// 一次快速排序
	public static int Partition(int arr[], int low, int high) {
		int pivotkey = arr[low];
		while (low < high) {
			while (low < high && arr[high] >= pivotkey)
				high--;
			arr[low] = arr[high];
			while (low < high && arr[low] <= pivotkey)
				low++;
			arr[high] = arr[low];
		}
		arr[low] = pivotkey;
		return low;
	}

	public static int moreThanHalf(int arry[], int start, int end) {
		if (arry == null || arry.length <= 0)
			return -1;
		int index = Partition(arry, start, end);
		int middle = arry.length / 2;
		while (index != middle) {
			if (index > middle)
				index = Partition(arry, start, index - 1);
			else
				index = Partition(arry, index + 1, end);
		}

		if (!CheckMoreThanHalf(arry, arry.length, arry[middle]))
			return -1;
		
		return arry[middle];
	}

	// 检查result是否在arry中出现超过一半
	public static boolean CheckMoreThanHalf(int arry[], int len, int result) {
		int time = 0;
		for (int i = 0; i < len; i++) {
			if (arry[i] == result)
				++time;
		}

		boolean isMoreThanHalf = true;
		if (time * 2 <= len)
			isMoreThanHalf = false;
		return isMoreThanHalf;
	}

	public static void main(String[] args) {
		int arr[] = { 2, 2, 1, 1, 1, 1, 3 };// 定义数组

		int half = moreThanHalf(arr, 0, arr.length - 1);
		System.out.println(half);
	}
解法二:

遍历数组时保存两个值,一个是数组中的数字,一个是出现的次数,遍历到一个数字时,

如果次数为零:遍历下一个数组元素,并把次数设为一。

如果次数不为零:

   如果该数字和之前保存的数字相同,则次数加一,
   如果该数字和之前保存的数字不同,则次数减一,

要找的数字肯定是最后一次把次数设为1时对应的数字。

	// 检查result是否在arry中出现超过一半
	public static boolean CheckMoreThanHalf(int arry[], int len, int result) {
		int time = 0;
		for (int i = 0; i < len; i++) {
			if (arry[i] == result)
				++time;
		}

		boolean isMoreThanHalf = true;
		if (time * 2 <= len)
			isMoreThanHalf = false;
		return isMoreThanHalf;
	}

	public static int moreThanHalfNum(int[] numbers, int length) {

		if (numbers == null && length <= 0) {
			return -1;
		}

		int result = 0;
		int times = 0;
		for (int i = 0; i < length; ++i) {
			if (times == 0) {
				result = numbers[i];
				times = 1;
			} else {
				if (numbers[i] == result)
					times++;
				else
					times--;
			}
		}

		if (!CheckMoreThanHalf(numbers, length, result))
			return -1;
		return result;
	}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值