我用的传统的二分查找方法,在mid点处分别求它的prevSlope和postSlope,这个过程中用一个slope函数来处理一些边界情况,防止mid 等于start 或 end 的时候会越界。
譬如如果去掉边界处理,在如下testcase中就会报错(虽然我觉得这个testcase并不严格符合题目的描述)。
public class Solution {
/**
* @param nums a mountain sequence which increase firstly and then decrease
* @return then mountain top
*/
public int mountainSequence(int[] nums) {
// Write your code here
if (nums == null || nums.length == 0) {
return Integer.MAX_VALUE;
}
int start = 0;
int end = nums.length - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (slope(mid, nums) > 0 && slope(mid + 1, nums) < 0) {
return nums[mid];
} else if (slope(mid, nums) > 0) {
start = mid;
} else {
end = mid;
}
}
if (slope(start, nums) > 0 && slope(start + 1, nums) < 0) {
return nums[start];
} else {
return nums[end];
}
}
private int slope(int node, int[] nums) {
if (node == 0) {
return 1;
}
if (node == nums.length) {
return -1;
}
return nums[node] - nums[node - 1];
}
}
Version#2
看了答案以后发现这道题实际上应该用三分法查找。关于三分法在网上找到了一篇讲解讲得很清楚。
三分查找适合用来查找最值。
三分查找
于是修改答案:
public class Solution {
/**
* @param nums a mountain sequence which increase firstly and then decrease
* @return then mountain top
*/
public int mountainSequence(int[] nums) {
// Write your code here
if (nums == null || nums.length == 0) {
return Integer.MAX_VALUE;
}
int start = 0;
int end = nums.length - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
int midmid = mid + (end - mid) / 2;
if (nums[mid] > nums[midmid]) {
end = midmid - 1;
} else if (nums[mid] < nums[midmid]) {
start = mid + 1;
} else {
start = mid;
end = midmid;
}
}
if (nums[start] > nums[end]) {
return nums[start];
} else {
return nums[end];
}
}
}
助教您好:
(刚刚看到ladder里面新加了一些题目。。。结果后面的题被锁住做不了了, 好悲伤!)
我想请问这个http://www.jiuzhang.com/solutions/maximum-number-in-mountain-sequence/答案使用的三分法里面,
int m1 = left + (right - left) / 2;
int m2 = right - (right - m1) / 2;
我把这里m2展开以后发现是 right / 2 + (right + left) / 4, 不太理解它的意义是什么?
我自己的答案写的是:
int m2 = m1 + (right - m1) / 2, 代表着在中点和右端点之间再取一次中点,但是这样就在[1,2,4,8,6,3] 的testcase里面报错了。不知道是什么问题?
谢谢!
(刚刚看到ladder里面新加了一些题目。。。结果后面的题被锁住做不了了, 好悲伤!)
我想请问这个http://www.jiuzhang.com/solutions/maximum-number-in-mountain-sequence/答案使用的三分法里面,
int m1 = left + (right - left) / 2;
int m2 = right - (right - m1) / 2;
我把这里m2展开以后发现是 right / 2 + (right + left) / 4, 不太理解它的意义是什么?
我自己的答案写的是:
int m2 = m1 + (right - m1) / 2, 代表着在中点和右端点之间再取一次中点,但是这样就在[1,2,4,8,6,3] 的testcase里面报错了。不知道是什么问题?
谢谢!
P.S.今天把我自己的答案改成int m2 = m1 + (right - m1) / 2 + 1 之后发现运行正确了。然而还是不理解这么取的意义是什么。。。
P.P.S 我发现这个问题发生在start 和end 中间只间隔一个数的情况下,譬如:
index 3 4 5
value 8 6 3
此时left = #3, right = #5, 所以m1 == m2 == #4, 就会造成 6是最大值的错误答案。而老师的标答中通过 right - (right - m1) / 2 这个公式,使得start 和 end中间只相隔一个数的情况下,m1 和 m2 也不会相等。 不知道我理解的对不对?
但是我感觉这个边界情况如果第一次做的话很难想得周全。。。不知道可不可以借鉴老师在二分法中的模板,把while 循环的条件改成 left + 2 < right就退出, 然后再进行判断,这样的做法是不是更加general一点呢?
另外很想问题下老师求解m2的公式如果是第一次做的话是怎么想出来的,思路是什么? 谢谢!
index 3 4 5
value 8 6 3
此时left = #3, right = #5, 所以m1 == m2 == #4, 就会造成 6是最大值的错误答案。而老师的标答中通过 right - (right - m1) / 2 这个公式,使得start 和 end中间只相隔一个数的情况下,m1 和 m2 也不会相等。 不知道我理解的对不对?
但是我感觉这个边界情况如果第一次做的话很难想得周全。。。不知道可不可以借鉴老师在二分法中的模板,把while 循环的条件改成 left + 2 < right就退出, 然后再进行判断,这样的做法是不是更加general一点呢?
另外很想问题下老师求解m2的公式如果是第一次做的话是怎么想出来的,思路是什么? 谢谢!
Version#3 我自己想的更改退出条件的做法
这个自己想出来的做法虽然看着有点丑陋但是思路非常直接,而且没有很多edge case需要考虑,感觉比较适合我。
写的过程中唯一一个bug是没有考虑到只有一个输入值的情况,这里在最前边加以讨论了。同理也可以放在最后当做 left == right的一个情况讨论。
public class Solution {
/**
* @param nums a mountain sequence which increase firstly and then decrease
* @return then mountain top
*/
public int mountainSequence(int[] nums) {
// Write your code here
if (nums == null || nums.length == 0) {
return Integer.MAX_VALUE;
}
if (nums.length == 1) {
return nums[0];
}
int left = 0;
int right = nums.length - 1;
while (left + 2 < right) {
int mid = left + (right - left) / 2;
int midmid = mid + (right - mid) / 2;
if (nums[mid] < nums[midmid]) {
left = mid + 1;
} else if (nums[mid] > nums[midmid]) {
right = midmid - 1;
} else {
left = mid + 1;
right = midmid - 1;
}
}
int tempMax = Math.max(nums[left], nums[right]);
if (right == left + 1) {
return tempMax;
} else {
return Math.max(tempMax, nums[left + 1]);
}
}
}
No comments:
Post a Comment