一维数组虽然是最基础的数据结构,但是题目技巧性却很强,总的来说可以涉及到各种依赖两个指针的遍历,不管是两个指针从左到右,还是从两端到中间,还是从左到右+从右到左。
一、从左到右+从右到左
这种变态的解题我还是第一次从leetcode中见识到,居然还有两道!
题目一:Candy
There are N children standing in a line. Each child is assigned a rating value. You are giving candies to these children subjected to the following requirements:
思路:这道题有点离散数学的感觉。这道题已经忘记了是不是自己独立做完的,反正当时尝试了一种很笨重的贪心的调整方法,O(n^2)超时。这道题先让所有的小朋友糖果数初始化为1,然后从左到右保证rating上升的孩子糖果数叶上升;然后从右到左保证rating上升糖果数也保存上升。两遍遍历O(n).
class Solution {
public:
int candy(vector &ratings) {
int candies[ratings.size()];
for(int i=0;iratings[i-1]&&candies[i]<=candies[i-1])
candies[i]=candies[i-1]+1;
}
for(int i=ratings.size()-2;i>=0;i--){
if(ratings[i]>ratings[i+1]&&candies[i]<=candies[i+1])
candies[i]=candies[i+1]+1;
}
int res=0;
for(int i=0;i
思路:这道题我最开始是将数组分成两半,分别求每一半的一次transaction的最大值,结果O(n^2)超时,太凶残了。没办法,再次求助了discuss。版主给了一个很巧妙的方法。先从左到右,求出每天价格较valley能赚的钱。然后从右到左,求出每天价格与peak的差。
class Solution {
public:
int maxProfit(vector &prices) {
int maxprofit=0;
const int n=prices.size();
if(n==0) return 0;
int valley=prices[0];
int peak=prices[n-1];
int hisProfit[n];
int futProfit[n];
memset(hisProfit, 0, sizeof(hisProfit));
memset(futProfit, 0, sizeof(futProfit));
for(int i=0; i0){
hisProfit[i]=max(hisProfit[i-1], prices[i]-valley);
}
}
for(int i=n-1; i>=0; i--){
peak=max(peak, prices[i]);
if(i
说明:这里求two transaction本以为他们是不可分开的,只能在每中数组划分下各自求出一个解。没想到这里将两次transaction分开来求。
二、一个指针从左到右遍历
之前的xSum基本都是两个指针分别从两端到中间解决的。这是从左到右遍历,辅以其他指针。
题目三:Sort Colors
Given an array with n objects colored red, white or blue, sort them so that objects of the same colors are adjacent, with the colors in the order red, white and blue. Here, we will use integers 0, 1, and 2 to represent the color red, white, and blue respectively. Note: you are not suppose to use the library's sort function!
思路:说实话,看到这道题我是完全没有思路(如果不能用counting sort的话)。看的discuss才知道的。分别有两者指针指向头和尾巴,头指针表示0的结束为止,尾指针表示2的开始为止。另外还有一个指针负责从左到右遍历数组。
class Solution {
public:
void sortColors(int A[], int n) {
int i = 0, j = n-1;
for (int k = 0; k <= j; k++) {
switch (A[k]) {
case 0: //如果是0,头指针的值与当前位置交换
A[k] = A[i];
A[i++] = 0;
break;
case 1: //如果是1,直接忽略,往下一步走
break;
case 2: //如果是2,尾指针的值与当前位置的值交换,并且当前位置需后退一步!
A[k--] = A[j];
A[j--] = 2;
break;
}
}
}
};
说明:这里本质上有三个指针,其中负责遍历的指针k在头指针和尾巴指针之间。所以k之前的值都是遍历过的值,而且只可能是0或者1。k之后的都是没遍历过的,如果k的值与尾指针交换,那么k--后退一步,重新遍历新值。
题目四:First Missing Positive
Given an unsorted integer array, find the first missing positive integer. For example, given [1,2,0], return 3. Your algorithm should run in O(n) time and uses constant space.
思路:这道题也很难,至少对于我来说。看了别人的解法。给出的是一种完全in-place算法。因为都是数字,所以算法有点各归各位的感觉。从左到右依次遍历,每个位置的而数字放在他们应该在的位置(做交换,后推)。
class Solution {
public:
int firstMissingPositive(int A[], int n) {
if(n==0) return 1;
for(int i=0; i0 && A[i]!=i+1){ //n意外的不用考虑
if(A[A[i]-1]!=A[i]){ //如果这里是等于好,那么就是重复!
swap(A[A[i]-1], A[i]); //通过置换将当前位置放回该放的位置,
i--; //交换后需后退一步重新遍历这个位置
}
}
}
for(int i=0; i
说明:上面这两道题都是从左到右遍历,但是技巧性挺强的。
题目五:Remove Duplicates from Sorted Array
Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. Do not allocate extra space.
思路:一次从左到右的遍历,用新index控制新数字的位置!
class Solution {
public:
int removeDuplicates(int A[], int n) {
if(n==0) return 0;
int newlen=1;
for(int i=1;i
题目六:Remove Duplicates from Sorted Array II
Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? For example, given sorted array A=[1,1,1,2,2,3], You function should return length=5, and A is now [1,1,2,2,3]
思路:记录每个重复数字出现的次数,如果次数超过2,则忽略;
class Solution {
public:
int removeDuplicates(int A[], int n) {
if(n==0) return 0;
int newlen=1;
int count=1;
for(int i=1;i//出现新元素的情况
A[newlen++]=A[i];
count=1;
}
}
return newlen;
}
};
题目七:Longest Consecutive Sequence
Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example, Given [100, 4, 200, 1, 3, 2], the longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. Your algorithm should run in O(n) complexity.
思路:这道题很明显需要一种排序的功能,但是又不能之间使用排序。有一种补救的方向,那就是具有排序功效的数据结构!
class Solution {
public:
int longestConsecutive(vector &num) {
if(num.size()==0) return 0;
set buf;
for(int i=0;i::iterator it=buf.begin();
int pre=*it;
for(++it; it!=buf.end();it++){
if(*it-pre!=1){
if(cnt>maxlen) maxlen=cnt;
cnt=0;
}
cnt++;
pre=*it;
}
if(cnt>maxlen) maxlen=cnt; //老是忘记这句该如何是好!
return maxlen;
}
};