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

1. 二维数组中的查找(剑指offer-3)

题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

解题思路:从二维数组的右上角(或左下角)的元素开始判断,因为此元素是它所在行的最大数,是它所在的列的最小数

如果它等于要查找的数字,则查找过程结束。

如果它大于要查找的数字,则可以排除它所在的列。

如果它小于要查找的数字,则可排除它所在的行。

这样如果要查找的数字不在数组的右上角,则每次判断都可以排除一行或一列以缩小查找范围,直到找到要查找的数字,或者查找范围为空。

下图是在二维数组中查找7的示意图:

java代码实现:

public static void main(String[] args) {
		int[][] arr = { { 1, 2, 8, 9 }, { 2, 4, 9, 12 }, { 4, 7, 10, 13 },
				{ 6, 8, 11, 15 }, { 8, 10, 14, 17 } };
		System.out.println(FindArray(arr, 5, 4, 8));// true
		System.out.println(FindArray(arr, 5, 4, 22));// false
	}

	// rows--二维数组行数(arr.length)
	// columns--二维数组列数(arr[0].length)
	// number--要查找的数
	public static boolean FindArray(int[][] arr, int rows, int columns,
			int number) {
		boolean found = false;
		if (arr != null && rows > 0 && columns > 0) {
			int row = 0;
			int column = columns - 1;
			while (row < rows && column >= 0) {
				if (arr[row][column] == number) {
					found = true;
					break;
				} else if (arr[row][column] > number) {
					column--;
				} else {
					row++;
				}
			}
		}

		return found;
	}

2.旋转数组的最小数字(剑指offer-8)

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.

解题思路:

1.我们用两个指针,分别指向数组的第一个元素和最后一个元素。按照题目旋转的规则,第一个元素应该是大于或者等于最后一个元素的(还有特例)。

2.接着我们得到处在数组中间的元素。如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间 元素的后面。我们可以把第一指针指向该中间元素,这样可以缩小寻找的范围。

3.如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。我们可以把第二个指针指向该中间元素,这样同样可以缩小寻找的范围。我们接着再用更新之后的两个指针,去得到和比较新的中间元素,循环下去。


按照上述的思路,我们的第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最后第一个指针将指向前面子数组的最后一个元素, 而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。这就是循环结束的条件。

java代码:

public static int MinNumber(int[] numbers , int length)
	{
	    if(numbers == null || length <= 0)
	        return 0;
	 
	    int index1 = 0;
	    int index2 = length - 1;
	    int indexMid = index1;//旋转为0直接返回numbers[0]
	    while(numbers[index1] >= numbers[index2])
	    {
	        if(index2 - index1 == 1)
	        {
	            indexMid = index2;
	            break;
	        }
	 
	        indexMid = (index1 + index2) / 2;
	        //如果下标为index1、index2和indexMid指向的三个数字相等,则只能顺序查找
	        if(numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])
	            return MinInOrder(numbers , index1 , index2);
	 
	        if(numbers[indexMid] >= numbers[index1])
	            index1 = indexMid;
	        else if(numbers[indexMid] <= numbers[index2])
	            index2 = indexMid;
	    }
	    return numbers[indexMid];
	}
	 
	//顺序查找
	public static int MinInOrder(int []numbers , int index1 , int index2)
	{
	    int result = numbers[index1];
	    for(int i = index1 + 1 ; i <= index2 ; ++i)
	    {
	        if(result > numbers[i])
	            result = numbers[i];
	    }
	    return result;
	}
注意:当两个指针指向的数字及他们中间的数字三者相同的时候,我们无法判断中间的数字是位于前面的字数组还是后面的子数组中,也就无法移动两个指针来缩小查找的范围。此时,我们不得不采用顺序查找的方法。


3.调整数组顺序使奇数位于偶数前面(剑指offer-14)
题目:
输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。

解析:设2个头尾指针begin和end, begin从头往前遍历,遇到奇数的话,说明这个数在在正确的位置,所以继续往前遍历直到遇到第一个偶数。同样end指针从后往前遍历,遇到偶数的话,说明这个数在正确的位置,所以继续往前遍历,直到遇到第一个奇数。交换着2个数,然后继续上两步操作,只要满足begin<end;

	// 调整数组顺序使奇数位于偶数前面
	public static void Reorder(int[] pData, int length) {
		if (pData == null || length == 0)
			return;

		int begin = 0;
		int end = length - 1;

		while (begin < end) {

			while (pData[begin] % 2 == 1)
				begin++;// 从前往后读到第一个偶数
			while (pData[end] % 2 == 0)
				end--;// 从后往前,读到第一个奇数

			if (begin < end)// 这个if是有必要的,不然如果事先已经有序的话,奇偶数交界处的2个数会被调换过来
			{
				// 交换前面的第一个偶数和后面的第一个奇数
				pData[begin] = pData[begin] ^ pData[end];
				pData[end] = pData[begin] ^ pData[end];
				pData[begin] = pData[begin] ^ pData[end];
				begin++;
				end--;
			}
		}
	}

后续: 数据结构---数组(2)




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值