[Algorithm] exercises power button array Exercises (1): Sheng most water containers

Description original title :

Given n non-negative integers a1, a2, ..., an, a point (i, ai) each represents the number of coordinates. Videos n lines in vertical coordinate, i is a vertical line two end points are (i, AI) and (i, 0). Find out the two lines, which together with the container so that the x-axis configuration can accommodate up water.

Note: You can not tilting the container, and the value of n is at least 2.


Original title link : https: //leetcode-cn.com/problems/container-with-most-water


 Solution one: violence to solve

To get the first idea of ​​solving the problem is solved violence. Set two cycles, the first layer is used to traverse the vessel left height, the height of the right side of the second layer is used to traverse the vessel. Then determine the infinitive is (container area) compare the size of the problem solution.

Given an array of side represents the height of the container is int [] height, my thought process is:

1. The two layers are circulating loop variable pre (left side of container height) and the post (the right container height)

2. Two boundary loop variable respectively

pre<height.length-1
post<height.length

3. Determine the area size comparison of container infinitive

maxsize = Math.max(maxsize, (Math.min(height[pre], height[post]))*(post-pre));    	

4. again before the end of each loop, the loop variable iteration. Special attention here to the right height is the height of the iterations on the basis of the left

After completing the above analysis, we can write the solution as follows:

 1 public int maxSize(int[] height) {
 2     if(height.length < 2 || height == null)
 3         return 0;
 4     
 5     int pre = 0, post = 1;
 6     int maxsize = 0;
 7     while(pre<height.length-1) {
 8         while(post<height.length) {
 9             maxsize = Math.max(maxsize, (Math.min(height[pre], height[post]))*(post-pre));            
10             post++;
11         }          
12         pre++;
13         post = pre + 1;
14     }
15     return maxsize;
16 }

Commissioning of the first pass, then two errors:

1) Line 9 comparison code occurs in the height of both sides is that the use of subscripts is not height value;

2) does not consider the first four points, i.e. 13 lines of code, so that the loss of some capacity of Length combination.

 

Solution two: try to optimize the solution (failed)

It is easy to think of this question should be a two-pointer is relevant. And two pointers are in line with the inertia of thinking end of the traverse to the right from the left end of the array, the idea is to consider appropriate, when a right pointer traversal, the left pointer according to the results of the comparison area size changes also followed.

I was considering three cases:

1) new area traversed container

int snew = (Math.min(height[pre], height[post]))*(post-pre);

2) Consider the left hand side of the adjacent area of ​​the container

int k = (height[pre+1]>height[pre])? (pre+1): pre;//for the next
int snext = (Math.min(height[k], height[post]))*(post-k);   

3) Considering the area in the vessel left and right hand sides of the maximum range (a left pointer)

j = (height[post]>height[j])? post: j;//for the highest
int shigh = (Math.min(height[j], height[post]))*(post-j);  

 By then comparing the three cases the size of the area on the container step, the iterative left pointer.

if(size == snext && k != pre) {pre++;}
if(size == shigh && j != pre) {pre=j;}

Consider the first (2) case, that was used in place of the normal cycle of violence can be solved, but when problems here is that if the height of the adjacent elements are equal, using whichever is greater attempt iterations to fail ;

So having regard to section (3) case, that is, within the scope of the right pointer has traversed singled out as the maximum edge length, this time it seems to me, it should be a supplement. (Now think, if there is (3), there is no need (2) a)

Because the understanding of this question, my idea is right pointer traversal has been able to ensure that the case involved the right side of the container are included. The left side just need to find the maximum length about the current pointer traversal range, you can ensure that the largest area of ​​the container.

Solution as follows:

 1 public int maxSize(int[] height) {
 2     if(height.length<2 || height == null)
 3         return 0;
 4     
 5     int pre = 0;
 6     int post = height.length-1;
 7     int maxsize = 0;
 8     while(pre<post) {
 9         int newsize = Math.min(height[pre], height[post])*(post-pre);
10         maxsize = Math.max(maxsize, newsize);
11         if(height[pre]>height[post])
12             post--;
13         else
14             pre++;
15     }
16     return maxsize;
17 }

Later in the test sample [75,21,3,152,13,107,163,166,32,160,41,131,7,67,56,5,153,176,29,139,61,149,176,142,64,75,170,156,73,48,148,101,70,103,53,83,11,1 ... It is given] time. I guess the reason, the situation can only be traversed incomplete.

 

Solution three: two-pointer (the reference answer, their solution, failed)

Official answers from both ends of the double pointer array to the intermediate traversed. But I am most worried about is whether there has been traversed again have access to all of the circumstances?

My own idea is that each pointer from the mobile or to judge. In the left pointer, for example, if the left pointer array element value of +1 (height) less than or equal to the left pointer array element value, taking into account the entire width of the container is also reduced thus, can not necessarily greater than the original area.

Accordingly, whenever a pointer is moved a certain area becomes larger, until all array elements to traverse the pointer ends toward the middle. But in this case, we found that the pointer does not move ...... later thought, or because the array element may be repeated, so that the pointer does not move. Compare confirms once again the size of the move will not work here

code show as below:

 1 public int solution4(int[] height) {
 2     if(height.length<2 || height == null)
 3         return 0;
 4     
 5     int pre = 0;
 6     int post = height.length-1;
 7     int maxsize = Math.min(height[pre], height[post])*(post-pre);
 8     while(pre<post) {
 9         int leftheight = Math.max(height[pre], height[pre+1]);
10         pre = (height[pre]<height[pre+1])?(pre+1):pre;
11         int rightheight = Math.max(height[post-1], height[post]);
12         post = (height[post]<height[post-1])?(post-1):post;
13         int newsize = Math.min(leftheight, rightheight)*(post-pre);
14         
15         maxsize = Math.max(maxsize, newsize);        
16     }
17     return maxsize;
18 }

 

Solution four: two-pointer (the standard answer)

First affix the official solution:

 1 public int solution3(int[] height) {
 2     if(height.length<2 || height == null)
 3         return 0;
 4     
 5     int pre = 0;
 6     int post = height.length-1;
 7     int maxsize = 0;
 8     while(pre<post) {
 9         int newsize = Math.min(height[pre], height[post])*(post-pre);
10         maxsize = Math.max(maxsize, newsize);
11         if(height[pre]>height[post])
12             post--;
13         else
14             pre++;
15     }
16     return maxsize;
17 }

 Solution two reason to consider such a fine, because it fears of a double pointer to traverse the analysis is not enough that there will always miss some combination. Three and a solution because the official start to feel the solution, but more about the elements of a pointer value, a certain feeling of lack of analysis?

After reading another solution to a problem and I found that this idea is complete.

Is defined as the left pointer I , and the right pointer to J , each case ( i, J ) on both sides as the sides of the container

So a total of two cases, three consider node

(1) is the initial situation

(2) a hand movement, there are two nodes, i.e., left and right hand movement pointer movement (essentially the same) -

First consider the left pointer,

If $ h (i) <h (j) $, then disposed around any node k within the range pointer, combinations $ X = \ {(i, k) | i <k \ le j \} $ are possible excluded.

Given all of case

 $\forall(i, k) \in X, H(i, k)=\left\{\begin{array}{l}{h(i) *(k-i), h(i) \leq h(k)} \\ {h(k) *(k-i), h(i)>h(k)}\end{array}\right.$

For $ h (i) <h (k) $, as shown, there are

$ H (i) * (ki) \ leq h (i) * (ji) $ (blue area smaller than the red area)

For $ h (i)> h (k) $, as shown, there are

$ H (k) * (ki) \ leq h (i) * (ki) <h (j) * (ji) $ (blue red area smaller than the area)

In summary, the $ h (i) <h (j) $, $ h (j) * (ji) $ already include / exclude all other combinations, so only need to look at $ h (i + 1)? H case (j) $ of the can, which can be safely iterative $ i $

Although the area after $ i $ iteration may be smaller, but allows the algorithm by comparing the size of the area to continue to traverse.

For the right hand, the same situation. Therefore traverse to the intermediate left and right sides of the pointer, may contain all the combinations.


 

 to sum up:

  • From both ends of the double pointer array to traverse the intermediate solution is the basis of
  • Demonstrated by the case can be traversed by all possible, it is safe according to the double pointer

 

 

 

 

Guess you like

Origin www.cnblogs.com/RicardoIsLearning/p/12015085.html