(简单)
描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
示例
输入:
[3,4,5,1,2]
返回值:
1
本题中关于此原始数组的其中一个描述是非递减排序的数组,这个名词我们千万不能理解错了,非递减排序的正确意思是,数据递增排列,但并非单调递增(因为可能有多个相等的数据的情况),即数列整体上从小到大并且允许其中有相等的情况出现。
而此题中的旋转数组,也就是根据非递减排序的数组经过旋转生成的,因此,针对 [1, 2, 3, 4, 5]这样一个非递减排序的数组,经过旋转后的全部可能排列情况为:
12345
23451
34512
45123
51234
因为旋转后的数组,在整体上,仍是有序的,并且这种有序的性质是可能集中有序于左部分,或右部分,因此,我们不难联想到二分法,我们完全可以定义一个 start 起始下标,end 末尾下标,mid 中间下标。我们在编码的循环中,以 start != end 为终止循环的条件,并在循环体中不断缩小查找范围,最终定位最小元素值。接下来我们便可以根据上面的排序样例分析,在循环体中,如果中值大于尾值,那么我们可以判定最小值在位置的右半部分,并且最小值不可能是中值或者说不可能和中值相等,因此我们便可将头值下标指向中值下标的下一位,若中值小于尾值,则最小值在左部分,并且需将尾下标指向中值下标,因为中值也在最小值的可能范围内。最后还需注意的一点就是题目中的 NOTE:若数组大小为0,则返回0。
上述算法思想也可以再进行进一步的优化,就12345这种排序情况,我们没必要再进入循环体比较,因为此题情况特殊,是由非递减排序的数组而生成的旋转数组,因此,当程序遇到这种整体递增(可能有等值,但不影响)的情况,只需通过 array[start] 小于 array[end] 成立,即可判断为此种情况,直接返回头值即可。另外,如果在其他情况中,循环体中出现了 array[mid] 等于 array[end] 的情况(这也意味着原始的非递减排序有数据相等的情况出现),我们可将尾下标进行一次左移动,从而避免之后不必要的判断,提高算法的执行效率,而此题也是卡的这一点,因为我在用 Java 代码进行提交时,没有这一步优化是会运行超时的。
class Solution3 {
public int minNumberInRotateArray(int [] array) {
if (array.length == 0) {
return 0;
}
int start = 0;
int end = array.length - 1;
int mid = 0;
while (start != end) {
// 优化1
if (array[start] < array[end]) {
return array[start];
}
//
mid = (start + end) / 2;
if (array[mid] > array[end]) {
start = mid + 1;
} else if (array[mid] < array[end]) {
end = mid;
}
// 优化2
else {
end--;
}
//
}
return array[start];
}
}
public class JZ6旋转数组的最小数字 {
public static void main(String[] args) {
Solution3 solution3 = new Solution3();
int[] array = new int[]{3, 4, 5, 1, 2};
int[] array2 = new int[]{4, 5, 1, 2, 3};
int[] array3 = new int[]{5, 1, 2, 3, 4};
int[] array4 = new int[]{3, 4, 1, 2};
int[] array5 = new int[]{2, 1};
int[] array6 = new int[]{1, 2, 3, 4};
System.out.println(solution3.minNumberInRotateArray(array));
System.out.println(solution3.minNumberInRotateArray(array2));
System.out.println(solution3.minNumberInRotateArray(array3));
System.out.println(solution3.minNumberInRotateArray(array4));
System.out.println(solution3.minNumberInRotateArray(array5));
System.out.println(solution3.minNumberInRotateArray(array6));
}
}
(简单)
描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
示例
输入:
{1,3,5},{2,4,6}
返回值:
{1,2,3,4,5,6}
此题为常见的两链表合并操作,只是在合并的同时要求结点值单调不递减。
在合并方法中,我们首先判断两个子链表的自身情况,若全为 null,那么我们返回 null 即可,若其中一个为 null,则我们返回另一个即可,而剩余的一种情况,即两个子链表都不为空时,我们需要首先建立一个存储最终合并结果的链表,而此链表我建议加上头结点,这样就可以使得此合并链表在空和非空状态时,能够保证操作的一致性(如果这里有疑问,自己两种方法都试一次,即有头结点,无头结点,便可知哪种是最优的),每次根据两个子链表的当前结点值进行比较,用较小的值,创建一个新的结点,并作为新结点的值,加入到合并链表中,不断重复此操作,直到其中一个链表已遍历结束,最终判断另一链表是否已遍历结束,若没有,则将其剩余结点按顺序加入到合并链表即可,因为题目中子链表本身的条件就是单调递增的,最终返回链表的第一个有效值结点即可,而不是返回整个链表,因为题中给出的测试数据便是这样要求的。
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
@Override
public String toString() {
return "ListNode{" +
"val=" + val +
", next=" + next +
'}';
}
}
class Solution6 {
public static ListNode Merge(ListNode list1,ListNode list2) {
if (list1 == null && list2 == null) {
return null;
} else if (list1 == null) {
return list2;
} else if (list2 == null) {
return list1;
} else {
ListNode mergeList = new ListNode(0);
ListNode tempList = mergeList;
while (list1 != null && list2 != null) {
if (list1.val > list2.val) {
tempList.next = new ListNode(list2.val);
tempList = tempList.next;
list2 = list2.next;
} else {
tempList.next = new ListNode(list1.val);
tempList = tempList.next;
list1 = list1.next;
}
}
while (list1 != null) {
tempList.next = new ListNode(list1.val);
tempList = tempList.next;
list1 = list1.next;
}
while (list2 != null) {
tempList.next = new ListNode(list2.val);
tempList = tempList.next;
list2 = list2.next;
}
return mergeList.next;
}
}
}
public class JZ16合并两个排序的链表 {
public static void main(String[] args) {
ListNode list1 = new ListNode(1);
//ListNode OList1 = list1;
//list1 = list1.next;
//list1 = new ListNode(3);
//list1 = list1.next;
//list1 = new ListNode(5);
list1.next = new ListNode(3);
list1.next.next = new ListNode(5);
ListNode list2 = new ListNode(2);
//ListNode OList2 = list2;
//list2 = list2.next;
//list2 = new ListNode(4);
//list2 = list2.next;
//list2 = new ListNode(6);
list2.next = new ListNode(4);
list2.next.next = new ListNode(6);
ListNode merge = Solution6.Merge(list1, list2);
showList(merge);
}
private static void showList(ListNode merge) {
while (merge != null) {
System.out.print(merge.val);
if (merge.next != null) {
System.out.print("——");
}
merge = merge.next;
}
}
}