[leetcode]20150704a
1、Container With Most Water
题目
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container.
思路
- 枚举所有组合肯定可以,O(n^2)
- 其他人的思路
harrifeng.github.io
最优解法非常巧妙,利用了常见的”双指针”法, 两个指针一个指向最前,一个指向最后, 然后 “数值小”的指针向里运动, 这里利用了”水桶的容积只取决于最断的那个木板”的原理!,最终 把复杂度降到了O(n).
其实是用贪心法。
直观的思想就是在缩小宽度的过程中,只有找到更高的木板,容积才可能更大。
所以每一步把短板(决定了容积大小的板)向内移动;
注意不用考虑短板固定,向内移动长板的情况,因为这样容积一定更小。
代码
int maxArea(int* height, int heightSize) {
if(heightSize == 0) return 0;
int max = 0;
int left = 0, right = heightSize-1;
while(left < right){
int contains = (height[left]<height[right]?height[left]:height[right]) * (right - left);
max = (max > contains? max : contains);
if(height[left]<height[right]) left ++;
else right --;
}
return max;
}
public class Solution {
public int maxArea(int[] height) {
if(height.length == 0) return 0;
int start = 0;
int end = height.length - 1;
int maxV = Integer.MIN_VALUE;
while (start < end) {
int contains = Math.min(height[end], height[start]) * (end - start);
maxV = Math.max(maxV, contains);
if (height[start] < height[end]) {
start ++;
} else {
end--;
}
}
return maxV;
}
}
总结
前段时间刷lintcode的时候看到过这道题,但是现在又忘记了。当时题目还有错误,原题是容器不可旋转,而翻译以后变成容器可以旋转了。现在又忘记当时的思路了,哎。。。
2、Rotate List
题目
Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.
思路
考察简单的数据结构-链表。
先计算链表长度为length,然后对k取mod length,shift = k % length,得到的值即为要右移位数,也就是链表的倒数第shift个元素变成链表头。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* rotateRight(struct ListNode* head, int k) {
if(head == NULL) return head;
if(k == 0) return head;
int length = 0;
struct ListNode* temp = head;
struct ListNode* temp2;
struct ListNode* tail;
while(temp != NULL){
length ++;
if(temp->next == NULL) tail = temp;
temp = temp->next;
}
if(length == 1) return head;
int shift = k % length;
if(shift == 0) return head;
int index = length - shift; //变成tail
temp = head;
int count = 0;
while(count < index){
count ++;
temp2 = temp;
temp = temp->next;
}
tail->next = head;
head = temp2->next;
temp2->next = NULL;
return head;
}
总结
C语言NULL需要大写;
用struct声明的结构体定义变量时,要在前面加上struct关键字。
3、Evaluate Reverse Polish Notation
题目
Evaluate the value of an arithmetic expression in Reverse Polish Notation.
Valid operators are +, -, *, /. Each operand may be an integer or another expression.
Some examples:
[“2”, “1”, “+”, “3”, ““] -> ((2 + 1) 3) -> 9
[“4”, “13”, “5”, “/”, “+”] -> (4 + (13 / 5)) -> 6
思路
考察简单的数据结构-栈。可是C语言怎么实现一个栈呢?貌似还是用普通的数组比较方便吧?
用C++实现的版本。
代码
class Solution {
public:
int evalRPN(vector<string> &tokens) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int len = tokens.size();
stack<int> S;
for(int i = 0; i < len; i++)
{
if(tokens[i] == "+" || tokens[i] == "-" ||
tokens[i] == "*" || tokens[i] == "/")
{
int op2 = S.top(); S.pop();
int op1 = S.top(); S.pop();
S.push( op(op1, op2, tokens[i][0]) );
}
else
S.push(stoi(tokens[i]));
}
return S.top();
}
int op(int op1, int op2, char optor)
{
if(optor == '+')return op1 + op2;
else if(optor == '-')return op1 - op2;
else if(optor == '*')return op1 * op2;
else return op1 / op2;
}
};
总结
1.熟悉C++标准模板库的使用;
2.练习用C实现常见的数据结构。
4、Subsets II
题目
Given a collection of integers that might contain duplicates, nums, return all possible subsets.
Note:
Elements in a subset must be in non-descending order.
The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,2], a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
思路
(X)和《数据结构基础》里看到的题目类似,用n个bool变量来枚举每个数字是否出现即可。
数字重复,上述方法不可行。
参考linhuanmars
这道题跟Subsets一样是经典的NP问题–求子集。比Subsets稍微复杂一些的是这里的集合中可能出现重复元素,因此我们在求子集的时候要避免出现重复的子集。在Subsets中我们每次加进一个元素就会把原来的子集都加上这个元素,然后再加入到结果集中,但是这样重复的元素就会产生重复的子集。为了避免这样的重复,需要用个小技巧。
其实比较简单,就是每当遇到重复元素的时候我们就只把当前结果集的后半部分加上当前元素加入到结果集中,因为后半部分就是上一步中加入这个元素的所有子集,上一步这个元素已经加入过了,前半部分如果再加就会出现重复。所以算法上复杂度上没有提高,反而少了一些操作,就是遇到重复时少做一半,不过这里要对元素集合先排序,否则不好判断重复元素。同样的还是可以用递归和非递归来解,不过对于重复元素的处理是一样的。递归的代码如下:
代码
public class Solution {
public List<List<Integer>> subsetsWithDup(int[] num) {
if(num == null)
return null;
Arrays.sort(num);
//Integer lastSize = 0; //仍然是值传递
ArrayList<Integer> lastSize = new ArrayList<Integer>();
lastSize.add(0);
return (List)helper(num, num.length-1, lastSize);
}
//lastSize的设置比较特殊,是递归调用子函数之后确定原ans大小的,所以要使用引用传递,不能是值传递
private ArrayList<ArrayList<Integer>> helper(int[] num, int index, ArrayList<Integer> lastSize)
{
if(index == -1)
{
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> elem = new ArrayList<Integer>();
res.add(elem);
return res;
}
ArrayList<ArrayList<Integer>> res = helper(num,index-1,lastSize);
int size = res.size();
int start = 0;
if(index>0 && num[index]==num[index-1]) //重复,只在上一次新增的部分加入当前元素
start = lastSize.get(0);
for(int i=start;i<size;i++)
{
ArrayList<Integer> elem = new ArrayList<Integer>(res.get(i));
elem.add(num[index]);
res.add(elem);
}
lastSize.set(0,size);
return res;
}
}
总结
- 求给定数组的全排列;
- 求给定数组的幂集。
5、Subsets (78)
题目
Given a set of distinct integers, nums, return all possible subsets.
Note:
Elements in a subset must be in non-descending order.
The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
思路
上一题的简化版,代码差不多。
因为上一题是特殊情况,所以上一题的代码对于这题完全是可用的。
同样参考了linhuanmars
代码
public class Solution {
public List<List<Integer>> subsets(int[] num) {
if(num == null)
return null;
Arrays.sort(num);
//Integer lastSize = 0; //仍然是值传递
ArrayList<Integer> lastSize = new ArrayList<Integer>();
lastSize.add(0);
return (List)helper(num, num.length-1, lastSize);
}
//lastSize的设置比较特殊,是递归调用子函数之后确定原ans大小的,所以要使用引用传递,不能是值传递
private ArrayList<ArrayList<Integer>> helper(int[] num, int index, ArrayList<Integer> lastSize)
{
if(index == -1)
{
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> elem = new ArrayList<Integer>();
res.add(elem);
return res;
}
ArrayList<ArrayList<Integer>> res = helper(num,index-1,lastSize);
int size = res.size();
int start = 0;
//if(index>0 && num[index]==num[index-1]) //重复,只在上一次新增的部分加入当前元素
//start = lastSize.get(0);
for(int i=start;i<size;i++)
{
ArrayList<Integer> elem = new ArrayList<Integer>(res.get(i));
elem.add(num[index]);
res.add(elem);
}
lastSize.set(0,size);
return res;
}
}
总结
经常出现 排列 和 组合 类题目。