Leetcode 第二章线性表--2.1数组---2.1.1 remove duplicate from sorted array--2017/7/23

来源:互联网 发布:农村选举知乎 编辑:程序博客网 时间:2024/06/07 07:29

2.1.1 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 for another array, you must do this in place with constant memory.
For example, Given input array A = [1,1,2],
Your function should return length = 2, and A is now [1,2].


问题1:vector不是模板 || list不是模板解决办法
解决方案:list和vector在命名空间std里,需要声明using namespace std;

问题2:非静态成员引用必须特定对象相对
解决方案:
意思就是引用非静态成员前应该先声明该类的对象。 
比如类A这样定义
class A
{
private:
int n;
}
要使用n就要先这样声明A的对象
A a;
a.n=1
或者也可以使用static,如
int static removeDuplicates(vector<int>& nums){
问题3:vector的初始化问题:
如果我们想用原始数组的内容填充vector,那么于有很多种方式。我们来一次学习vector的几个方法。
例如我们有数组int  v1[10] = {0,1,0,0,3,0,0,4,4,4};

方法1:

int B[10] = {0,0,0,0,0,1,3,4,4,4};   //原始数组
vector<int> A; //初始化size为10可以避免数组动态增长的时候不断的分配内存
for (int i = 0; i < 10; i++){
A.push_back(B[i]);  //增加一个元素
}

原则:尽量使用empty而不是size()==0 来判断容器是否为空


问题四:何谓时间复杂度,何谓空间复杂度?

参阅数据结构、算法与应用 C++语言描述 P38


举例子:

函数模板

//sequentialSearch顺序查找
#include <iostream>
using namespace std;

template<class T>
int sequentialSearch(T a[], int n, const T& x){
//在数组a[0:n-1]中查找元素X
//如果找到,则返回该元素的位置,否则返回-1
int i;
for (i = 0; i < n && a[i] != x; i++);
if (i == n) return -1;
else return i;
}


int main(){
int A[4] = { 1, 2, 3, 4 };
int B = 5;
cout << sequentialSearch(A, 4, B) << endl;
return 0;
}


问题5:

在使用distance(),unique( )等函数时要加入#include <algorithm>

她们是STL中的算法


问题6:C++中upper_bound

   

        C++中lower_bound函数和upper_bound函数

  STL中关于二分查找的函数有三个lower_bound 、upper_bound 、binary_search 。这三个函数都运用于有序区间(当然这也是运用二分查找的前提),下面记录一下这两个函数。

ForwardIter lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一个非递减序列[first, last)中的第一个大于等于值val的位置。

ForwardIter upper_bound(ForwardIter first, ForwardIter last, const _Tp& val)算法返回一个非递减序列[first, last)中的第一个大于值val的位置。

lower_bound和upper_bound如下图所示:

\

整体方法1:

#include <iostream>
#include <vector>
using namespace std;
// LeetCode, Remove Duplicates from Sorted Array
// 时间复杂度 O(n)空间复杂度 O(1)
class Solution{  
public:
int removeDuplicates(vector<int>& nums){   //形参是vector的一个引用
if (nums.empty()) return 0;     //使用了vector的empty()方法,判断是否为空


int index = 0;
for (int i = 1; i < nums.size(); i++){
if (nums[index] != nums[i])
nums[++index] = nums[i];
}
return index + 1;
}
};


int main(){
int B[10] = {0,0,0,0,0,1,3,4,4,4};   //原始数组
vector<int> A; //初始化size为10可以避免数组动态增长的时候不断的分配内存
for (int i = 0; i < 10; i++){
A.push_back(B[i]);  //增加一个元素
}
Solution mySolution;
int length = mySolution.removeDuplicates(A);
cout << length << endl;

for (int i = 0; i < length; i++){
cout << A[i] << endl;
}


return 0;
}

点评:结果是正确的,思路就是,若为空,则返回零,若不为空,则依次比较,发现后面的大于前面的了INDEX就增1,注意index初始化是0,所以返回长度需+1. 这里面,注意题干中提到是使用同一个VECTOR,不能分配其他的内存(使用其他的vector)


整体方法2:

class Solution{    //方法2 使用STL,时间复杂度O(N),空间复杂度O(1)
public:
int removeDuplicates(vector<int>& nums){
return distance(nums.begin(), unique(nums.begin(), nums.end()));  //unique返回地址 distance计算两个地址之间的距离
}
};


点评:

个人感觉,unique是STL中很实用的函数之一,需要#include<iostream>,下面来简单介绍一下它的作用。

unique的作用是“去掉”容器中相邻元素的重复元素,这里去掉要加一个引号,为什么呢,是因为它实质上是一个伪去除,它会把重复的元素添加到容器末尾,而返回值是去重之后的尾地址(是地址!!),举个例子:

[cpp] view plain copy print?
  1. int num[10]={1,1,2,2,2,3,4,5,5,5};  
  2. int ans=unique(num,num+10)-num;  

这时,返回的ans是5,而num中前5项就是1,2,3,4,5,一般使用前需要对容器进行排序,这样才能实现对整个数组去重。

另:如果要对结构体进行这一操作,需要重载运算符"==",具体要根据自己需要重载。

  使用stl中的  advance和 distance 方法来进行iterator的加减

           以前在遍历vector的时候,经常使用iterator之间的加减来获得元素在容器里面的index。

         今天在进行list的 iterator加减的时候,发现不能编译通过,后面想起list是非线性的容器,不能加减。

         查了一下资料,发现stl有提供两个iterator加减的方法:advance 和 distance

         advance是 将iterator移动,而distance是计算两个iterator之间的距离。


整体方法3:

class Solution{    //方法3 使用STL,时间复杂度O(N),空间复杂度O(1),主要是upper_bound()函数是STL中的函数
public:
int removeDuplicates(vector<int>& nums){
return distance(nums.begin(),removeDuplicates(nums.begin(),nums.end(),nums.begin()));
}


template <typename InIt, typename OutIt>  //函数模板,函数重载
OutIt removeDuplicates(InIt first, InIt last, OutIt output){
while (first != last){
*output++ = *first;
first = upper_bound(first, last, *first);
}
return output;
}
};
//怎么理解?首先把第一个给Output,Output地址加一,然后调用upper_bound,找第一个大于*first的地址,更新Output,最后返回的效果相当于unique返回地址


以下是taren做题过程中的一些体会:
1. LeetCode的题库越来越大,截止到目前,已经有321个问题了。对于大多数人来说,没有时间也没有必要把所有题目都做一遍(时间充裕可以随意)。刷个100题左右应该就差不多了(可以考虑序号为前100多的题目,相对更经典一点)。
2. 从AC率高的开始做,难度从简单->中等,先不要做困难的。
3. 可以按照下文的面试出题频率顺序来做,从频率最高的一批开始。
4. 尽量不使用IDE,直接在平台上写代码。
5. 不要看标签,不要看标签,不要看标签。标签相当于问题的分类,看了标签就会往那个方向去想,不利于自主思考。
6. 写好代码先不要提交,人工检查一下代码,比如分号是否都有写,return有没少等等。
7. 人工检查完后使用“Custom Testcase”功能自定义测试用例,注意检查边界,然后“Run Code”,这步可以发现蛮多问题的。
8. 等RunCode通过后,再去提交。






阅读全文
0 0
原创粉丝点击