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

来源:互联网 发布:考试通软件 编辑:程序博客网 时间:2024/05/16 05:01
1、数字在排序数组中出现的次数(剑指offer--38)
题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4.

思路:用二分查找,分别找出第一个3,和最后一个3的位置,然后计算个数。

public static int getLower(int arr[], int key) {int low = 0, high = arr.length - 1;while (low <= high) {int mid = (low + high) / 2;if (arr[mid] < key) {low = mid + 1;} else if (arr[mid] > key) {high = mid - 1;} else {if ((mid > 0 && arr[mid - 1] != key) || mid == 0) {return mid;} else {high = mid - 1;}}}if (low > high)return -1;return low;}public static int getUpper(int arr[], int key) {int low = 0, high = arr.length - 1;while (low <= high) {int mid = (low + high) / 2;if (arr[mid] < key) {low = mid + 1;} else if (arr[mid] > key) {high = mid - 1;} else {if ((mid < arr.length - 1 && arr[mid + 1] != key)|| mid == arr.length - 1) {return mid;} else {low = mid + 1;}}}if (low > high)return -1;return low;}public static int getNumberOfK(int arr[], int key) {if (arr == null)return -1;int number = 0;int first = getLower(arr, key);int last = getUpper(arr, key);if (first > -1 && last > -1)number = last - first + 1;return number;}

2、数组中只出现一次的数(剑指offer--40)

题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
通过这道题感觉位运算很强大,这道题利用异或的几个性质:任何数与其本身异或值都为0,异或运算满足交换律。因此将一组数依次异或,若里面只有一个只出现一次的数,其他的数都出现两次,则最后的结果必然是那个只出现一次的数。要找到两个数字就可以先通过异或整个数组,将得到的结果分组。然后依次安组异或就可以得到所求的值。

public static String findNums(int date[], int length) {if (length < 2) {return "|";}int ansXor = 0;for (int i = 0; i < length; i++) {ansXor ^= date[i]; // 异或}int pos = findFirstOne(ansXor);int num1 =0, num2 = 0;for (int i = 0; i < length; i++) {if (testBit(date[i], pos-1) == 1)num1 ^= date[i];elsenum2 ^= date[i];}return num1 + "|" + num2;}public static int findFirstOne(int value) { // 取二进制中首个为1的位置int pos = 1;while ((value & 1) != 1) {value = value >> 1;pos++;}return pos;}public static int testBit(int value, int pos) { // 测试某位置是否为1return ((value >> pos) & 1);}

3、和为S的两个数字VS和为s的连续正数序列(剑指offer--41)
题目:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
思路:最初我们找到数组的第一个数字和最后一个数字。首先定义两个指针,第一个指针指向数组的第一个(也就是最小的)数字,第二个指针指向数组的最后一个(也就是最大的)数字。当两个数字的和大于输入的数字时,把较大的数字往前移动;当两个数字的和小于数字时,把较小的数字往后移动;当相等时,打完收工。这样扫描的顺序是从数组的两端向数组的中间扫描。

public static String FindNumbersWithSum(int data[], int length, int sum) {if (length < 1 || data == null)return "";int end = length - 1;int start = 0;int curSum = 0;while (start < end) {curSum = data[start] + data[end];if (curSum == sum) {return data[start] + "+" + data[end] + "=" + curSum;} else if (curSum > sum)end--;elsestart++;}return "";}
题目:输入一个正数S,打印出所有和为S的连续正数序列(至少有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5,4~6和7~8.
有了解决前面问题的经验,这里也考虑两个数small和big分别表示序列的最小值和最大值。

首先把small初始化为1,big初始化为2.

如果从small到big的序列的和大于S,可以从序列中去掉较小的值,也就是增大small的值。

如果从small到big的序列的和小于S,可以增大big,让这个序列包含更多的数字。因为这个序列至少要有两个数字,我们一直增加small到(1+S)/2为止。

如果从small到big的序列的和等于S,输出序列,之后增大big。

public static void FindContinuousSequence(int sum) {if (sum < 3)return;int small = 1;int big = 2;int middle = (1 + sum) / 2;int curSum = small + big;while (small < middle) {if (curSum == sum) {String print = small + "";for (int i = small + 1; i <= big; i++) {print += "+" + i;}System.out.println(print+"="+curSum);big++;curSum +=big;} else if (curSum < sum) {big++;curSum +=big;} else {curSum -=small;small++;}}}
4、翻转句子中单词的顺序vs左旋字符串(剑指offer--42)
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。
例如输入“I am a student.”,则输出“student. a am I”。

分析:由于本题需要翻转句子,我们先颠倒句子中的所有字符。这时,不但翻转了句子中单词的顺序,而且单词内字符也被翻转了。

我们再颠倒每个单词内的字符。由于单词内的字符被翻转两次,因此顺序仍然和输入时的顺序保持一致。

还是以上面的输入为例子。翻转“I am a student.”中所有字符得到“.tneduts a ma I”,再翻转每个单词中字符的顺序得到“students. a am I”,正是符合要求的输出。

public static void reverse(char[] str, int start, int end) {if (str == null || start < 0 || end < 0)return;char temp;while (start < end) {temp = str[start];str[start] = str[end];str[end] = temp;start++;end--;}}public static void reverseSentence(char[] str) {if (str == null)return;// 翻转整个数组int len = str.length;reverse(str, 0, len - 1);int start = 0;int end = 0;// 翻转每个单词while (end < len) {if (end == len - 1) {reverse(str, start, end);}if (str[end] == ' ') {reverse(str, start, end - 1);end++;start = end;} else {end++;}}} 
题目:定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。 如把字符串abcdef左旋转2位得到字符串cdefab。
步骤:
先对每一部分旋转,abcdefg 变成bagfedc,之后,对整个字符串进行翻转。bagfedc - cdefgab

public static void reverse(char[] str, int start, int end) {if (str == null || start < 0 || end < 0)return;char temp;while (start < end) {temp = str[start];str[start] = str[end];str[end] = temp;start++;end--;}}// 左旋字符串(翻转前count字符)public static void reverseLeftSentence(char[] str, int count) {if (str == null || count < 1 || count > str.length)return;int start = 0;int end = str.length - 1;// 翻转单词reverse(str, start, count - 1);reverse(str, count, end);// 翻转句子reverse(str, start, end);}


0 0