定义:
由一个或多个确定的元素所构成的整体。
特性:
1.集合里的元素类型不一定相同。
2.集合里的元素没有顺序。
事实上,这样的集合并不直接存在于编程语言中。然而,实际编程语言中的很多数据结构,就是在集合的基础上添加了一些规则形成的。
定义:
一种数据项构成的有限序列,即按照一定的线性顺序,排列而成的数据项的集合。
列表的概念是在集合的特征上形成的,它具有顺序,且长度是可变的。
列表最常见的表现形式有数组和链表,而我们熟悉的栈和队列则是两种特殊类型的列表。
如何从宏观上区分列表和数组呢?这里有一个重要的概念:索引。
1.数组会用一些名为索引的数字来标识每项数据在数组中的位置,且在大多数编程语言中,索引是从 0 算起的。我们可以根据数组中的索引,快速访问数组中的元素。列表中没有索引,这是数组与列表最大的不同点。
2.数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存。列表中的元素在内存中可能彼此相邻,也可能不相邻。比如列表的另一种实现方式——链表,它的元素在内存中则不一定是连续的
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int a[10100];
memset(a,0,sizeof a);
int len=nums.size();
for(int i=1;i<=len;i++){
a[i]=a[i-1]+nums[i-1];
}
for(int i=1;i<=len;i++){
if(a[i-1]==a[len]-a[i]){
return i-1;
}
}
return -1;
}
};
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int len=nums.size();
int l=0,r=len-1;
while(l<r){
int mid=(l+r)/2;
if(nums[mid]>=target){
r=mid;
}else{
l=mid+1;
}
}
if(l==len-1&&target>nums[l])return l+1;
return l;
}
};
const int INF=-0x3f3f3f3f;
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>>ans;
sort(intervals.begin(),intervals.end());
int len=intervals.size();
int begin,end;
for(int i=0;i<len;i++){
vector<int>line;
int a=intervals[i][0],b=intervals[i][1];
if(!i){
begin=a;
end=b;
}
if(i&&a>end){
line.push_back(begin);
line.push_back(end);
ans.push_back(line);
begin=a;
end=b;
}else if(i&&a<=end){
end=max(end,b);
}
if(i==len-1){
vector<int>tail;
tail.push_back(begin);
tail.push_back(end);
ans.push_back(tail);
}
}
return ans;
}
};
只是将数组中的每个元素变成了一维数组
二维数组的本质上仍然是一个一维数组,内部的一维数组仍然从索引 0 开始,我们可以将它看作一个矩阵,并处理矩阵的相关问题。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int len=matrix.size();
for(int i=0;i<len;i++){
for(int j=0;j<i;j++){
swap(matrix[i][j],matrix[j][i]);
}
}
for(int i=0;i<len;i++){
for(int j=0;j<len/2;j++){
swap(matrix[i][j],matrix[i][len-j-1]);
}
}
}
};
法一:标记数组
最容易想到了就不写了
法二:使用两个标记变量
我们可以用矩阵的第一行和第一列代替方法一中的两个标记数组,以达到 O(1)O(1) 的额外空间。但这样会导致原数组的第一行和第一列被修改,无法记录它们是否原本包含 00。因此我们需要额外使用两个标记变量分别记录第一行和第一列是否原本包含 00。
在实际代码中,我们首先预处理出两个标记变量,接着使用其他行与列去处理第一行与第一列,然后反过来使用第一行与第一列去更新其他行与列,最后使用两个标记变量更新第一行与第一列即可。
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int n=matrix.size();
int m=matrix[0].size();
bool row=false,col=false;
for(int i=0;i<m;i++){
if(!matrix[0][i]){
row=true;
break;
}
}
for(int i=0;i<n;i++){
if(!matrix[i][0]){
col=true;
break;
}
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if(!matrix[i][j])matrix[0][j]=matrix[i][0]=0;
}
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if(!matrix[0][j]||!matrix[i][0])matrix[i][j]=0;
}
}
if(row){
for(int i=0;i<m;i++){
matrix[0][i]=0;
}
}
if(col){
for(int i=0;i<n;i++){
matrix[i][0]=0;
}
}
}
};
法三:使用一个标记变量
我们可以对方法二进一步优化,只使用一个标记变量记录第一列是否原本存在 00。这样,第一列的第一个元素即可以标记第一行是否出现 00。但为了防止每一列的第一个元素被提前更新,我们需要从最后一行开始,倒序地处理矩阵元素。
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int n=matrix.size();
int m=matrix[0].size();
bool col=false;
//注意先列再行不然行matrix[0][0]的改变会影响到列
for(int i=0;i<n;i++){
if(!matrix[i][0]){
col=true;
break;
}
}
for(int i=0;i<m;i++){
if(!matrix[0][i]){
matrix[0][0]=0;
break;
}
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if(!matrix[i][j])matrix[0][j]=matrix[i][0]=0;
}
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if(!matrix[0][j]||!matrix[i][0])matrix[i][j]=0;
}
}
if(matrix[0][0]==0){
for(int i=0;i<m;i++){
matrix[0][i]=0;
}
}
if(col){
for(int i=0;i<n;i++){
matrix[i][0]=0;
}
}
}
};
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
vector<int>ans;
int n=mat.size(),m=mat[0].size();
bool flag=true;
int pre;
pre=0;
int len=m+n;
for(int i=0;i<len*2-1;i++){
if(flag){
int row=pre;
int col=i-pre;
int b=2*len-i;
while(!(row>=0&&row<n&&col>=0&&col<m)&&b--){
row--;
col++;
}
while(row>=0&&row<n&&col>=0&&col<m){
ans.push_back(mat[row--][col++]);
}
pre=col;
}else{
int row=i-pre;
int col=pre;
int b=2*len-1-i;
while(!(row>=0&&row<n&&col>=0&&col<m)&&b--){
row++;
col--;
}
while(row>=0&&row<n&&col>=0&&col<m){
ans.push_back(mat[row++][col--]);
}
pre=row;
}
flag=!flag;
}
return ans;
}
};
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
string ans;
int len=strs.size();
int n=strs[0].size();
for(int i=0;i<n;i++){
auto c=strs[0][i];
int j;
for(j=1;j<len;j++){
if(c!=strs[j][i])break;
}
if(j==len){
ans+=c;
}else{
return ans;
}
}
return ans;
}
};
法二:
看了大佬的解法,超级巧妙
字典排序后,第一个串与最后一个串差异最大,找他们两的公共前缀,就是所有子串的公共前缀
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
string ans;
sort(strs.begin(),strs.end());
string st=strs[0],end=strs[strs.size()-1];
int len1=st.size(),len2=end.size();
int t=0;
while(t<len1&&t<len2&&st[t]==end[t]){
ans+=st[t];
t++;
}
return ans;
}
};
法一:暴力法,直接超时
class Solution {
public:
string longestPalindrome(string s) {
int len=s.size();
if(len<2)return s;
int begin=0;
int maxlen=1;
for(int i=0;i<len-1;i++){
for(int j=i+1;j<len;j++){
if(j-i+1>maxlen&&check(i,j,s)){
maxlen=j-i+1;
begin=i;
}
}
}
printf("%d",maxlen);
return s.substr(begin,maxlen);
}
bool check(int i,int j,string s){
int len=(j-i)/2;
for(int k=0;k<=len;k++){
if(s[i+k]!=s[j-k]){
return false;
}
}
return true;
}
};
法二:动态规划
const int N=1010;
class Solution {
public:
bool dp[N][N];
string longestPalindrome(string s) {
int len=s.size();
if(len<2||len==2&&(s[0]==s[1]))return s;
int begin=0,end=0;
memset(dp,0,sizeof dp);
for(int i=0;i<len;i++){
dp[i][i]=true;
if(i+1<len&&s[i]==s[i+1]){
dp[i][i+1]=true;
begin=i;
end=i+1;
}
}
for(int k=2;k<len;k++){
for(int i=0;i<len;i++){
if(i+k==len)break;
if(s[i]==s[i+k]&&dp[i+1][i+k-1]){
dp[i][i+k]=true;
if(k>end-begin){
begin=i;
end=i+k;
}
}
}
}
return s.substr(begin,end-begin+1);
}
};
法三:中心扩展法
const int N=1010;
typedef pair<int,int>PII;
class Solution {
public:
string longestPalindrome(string s) {
int len=s.size();
if(len==0||len==1)return s;
PII ans={0,0};
for(int i=0;i<len;i++){
auto t=check(i,i,s);
if(t.second-t.first>ans.second-ans.first){
ans=t;
}
t=check(i,i+1,s);
if(t.second-t.first>ans.second-ans.first){
ans=t;
}
}
return s.substr(ans.first,ans.second-ans.first+1);
}
PII check(int i,int j,string s){
PII ans;
int len=s.size();
int l=i,r=j;
while(s[l]==s[r]){
ans={l,r};
l--;
r++;
if(l<0||l>=len||r<0||r>=len)break;
}
return ans;
}
};
class Solution {
public:
string reverseWords(string s) {
int i=0,j=s.size()-1;
while(s[i]==' ')i++;
while(s[j]==' ')j--;
s=s.substr(i,j+1-i);
for(int i=0;i<s.size();i++){
int j=i;
while(j<s.size()&&s[j]!=' ')j++;
reverse(s.begin()+i,s.begin()+j);
if(j==s.size())break;
int p=j;
while(s[p+1]==' ')p++;
if(p!=j)s=s.substr(0,j+1)+s.substr(p+1,s.size()-p-1);
i=j;
}
reverse(s.begin(),s.end());
return s;
}
};
KMP
class Solution {
public:
int strStr(string haystack, string needle) {
int n=haystack.size();
int m=needle.size();
if(n==0&&m>0)return -1;
if((n==0||m==0)||haystack==needle)return 0;
int ans=0;
const int N=5e4+10;
int ne[N];
memset(ne,0,sizeof ne);
bool flag=false;
haystack=" "+haystack;
needle=" "+needle;
for(int i=2,j=0;i<=m;i++){
while(j&&needle[i]!=needle[j+1])j=ne[j];
if(needle[i]==needle[j+1])j++;
ne[i]=j;
}
for(int i=1,j=0;i<=n;i++){
while(j&&haystack[i]!=needle[j+1])j=ne[j];
if(haystack[i]==needle[j+1])j++;
if(j==m){
ans=i-m;
flag=true;
break;
}
}
if(!flag)return -1;
return ans;
}
};
class Solution {
public:
void reverseString(vector<char>& s) {
int len=s.size();
for(int i=0;i<len/2;i++){
swap(s[i],s[len-i-1]);
}
}
};
class Solution {
public:
int arrayPairSum(vector<int>& nums) {
int len=nums.size();
quicksort(0,len-1,nums);
int ans=0;
for(int i=0;i<len;i+=2){
ans+=nums[i];
}
return ans;
}
void quicksort(int l,int r,vector<int>&nums){
if(l==r)return;
int x=nums[l],i=l-1,j=r+1;
while(i<j){
do{i++;}while(nums[i]<x);
do{j--;}while(nums[j]>x);
if(i<j)swap(nums[i],nums[j]);
}
quicksort(l,j,nums);
quicksort(j+1,r,nums);
}
};
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int>ans;
int len=numbers.size();
int i=0,j=len-1;
int prei=0,prej=len-1;
while(i<=j){
if(numbers[i]+numbers[j]==target){
ans.push_back(i+1);
ans.push_back(j+1);
break;
}else if(numbers[i]+numbers[j]<target){
i++;
if(i==prei)break;
prei=i;
}else{
j--;
if(j==prej)break;
prej=j;
}
}
return ans;
}
};
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int len=nums.size();
int j=0;
for(int i=0;i<len;i++){
if(nums[i]!=val)nums[j++]=nums[i];
}
return j;
}
};
class Solution {
public:
int ans=0;
int findMaxConsecutiveOnes(vector<int>& nums) {
int len=nums.size();
for(int i=0;i<len;i++){
int j=i;
while(j<len&&nums[j]==1)j++;
ans=max(ans,j-i);
if(i!=j)i=j-1;
}
return ans;
}
};
class Solution {
public:
const int MAX=0x3f3f3f3f;
int ans=MAX;
int minSubArrayLen(int target, vector<int>& nums) {
int len=nums.size();
for(int i=0;i<len;i++){
int j=i,sum=0;
while(j<len&&sum<target){
sum+=nums[j++];
}
if(j==len&&sum<target)break;
if(sum>=target&&j-i!=0)ans=min(ans,j-i);
}
if(ans==MAX)return 0;
return ans;
}
};
class Solution {
public:
vector<vector<int>>ans;
vector<int>line;
vector<vector<int>> generate(int numRows) {
vector<vector<int>>ans=dfs(1,numRows);
return ans;
}
vector<vector<int>>dfs(int row,int end){
vector<int>preline=line;
line.clear();
if(row==1){
line.push_back(1);
}else if(row==2){
line.push_back(1);
line.push_back(1);
}else{
int len=preline.size();
line.push_back(1);
for(int i=0;i<len-1;i++){
line.push_back(preline[i]+preline[i+1]);
}
line.push_back(1);
}
ans.push_back(line);
if(row<end)dfs(row+1,end);
return ans;
}
};
class Solution {
public:
vector<int>line;
vector<int> getRow(int numRows) {
vector<int>ans=dfs(1,numRows+1);
return ans;
}
vector<int>dfs(int row,int end){
vector<int>preline=line;
line.clear();
if(row==1){
line.push_back(1);
}else if(row==2){
line.push_back(1);
line.push_back(1);
}else{
int len=preline.size();
line.push_back(1);
for(int i=0;i<len-1;i++){
line.push_back(preline[i]+preline[i+1]);
}
line.push_back(1);
}
if(row<end)dfs(row+1,end);
return line;
}
};
class Solution {
public:
string reverseWords(string s) {
int len=s.size();
for(int i=0;i<len;i++){
int j=i;
while(j<len&&s[j]!=' ')j++;
reverse(s.begin()+i,s.begin()+j);
i=j;
}
return s;
}
};
class Solution {
public:
int findMin(vector<int>& nums) {
int len=nums.size();
int l=0,r=len-1;
int high=nums[len-1];
while(l<r){
int mid=(l+r)/2;
if(nums[mid]<=high){
r=mid;
}else{
l=mid+1;
}
}
return nums[l];
}
};
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len=nums.size(),j=0;
for(int i=0;i<len;i++){
if(j==0||nums[i]!=nums[j-1]){
nums[j++]=nums[i];
}
}
return j;
}
};
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int len=nums.size(),j=0;
for(int i=0;i<len;i++){
if(nums[i]!=0){
nums[j++]=nums[i];
}
}
for(int i=j;i<len;i++){
nums[i]=0;
}
}
};