数组

写在前面:解决数组问题有一些常见的思路,下面,在这里,对相应问题进行汇总。


一.定义新的索引

283 remove zeros(将数组中的零元素移到末尾)

Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

Note:

  1. You must do this in-place without making a copy of the array.
  2. Minimize the total number of operations.

思考细节:

1.如何定义删除?从数组中去除?还是放在数组末尾?

2.剩余元素的排列是否要保证原有的相对顺序?

3.是否有空间复杂度的要求?O(1)

思路:

定义新的索引k,保存删除指定元素后的新的元素的位置。

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int k = 0;
		for(int i = 0; i < nums.size(); i++){
			if(nums[i]) {
				if(i!=k) {
					nums[k++] = nums[i];
					nums[i] = 0;
				}
				else k++;
			}
		}
    }

	/*
	void moveZeroes(vector<int>& nums) {
        int k = 0;
		for(int i = 0; i < nums.size(); i++){
			if(nums[i])nums[k++] = nums[i];
		}
		for(int i = k; i < nums.size(); i++){
			nums[i] = 0;
		}
    }
*/
};


=============================================================================

27 remove element(将数组中的指定元素移除)

Given an array and a value, remove all instances of that value in-place and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

The order of elements can be changed. It doesn't matter what you leave beyond the new length.

Example:

Given nums = [3,2,2,3], val = 3,

Your function should return length = 2, with the first two elements of nums being 2.

思路同上,将零元素换为指定要删除的元素。

class Solution {
public:
	int removeElement(vector<int>& nums, int val) {
        int k = 0;
		for(int i = 0; i < nums.size(); i++){
			if(nums[i] != val) {
				if(i!=k) {
					nums[k++] = nums[i];
					nums[i] = val;
				}
				else k++;
			}
		}
		return k;
    }
};



=============================================================================

26 remove duplicated 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 by modifying the input array in-place with O(1) extra memory.

Example:

Given nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the new length.

思路改动:需要移除的元素不是固定的,需要进行更新。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int k = 0;
        if(nums.size() == 0) return 0;
		int prev = nums[0];
		nums[k++] = nums[0];
		for(int i = 1; i < nums.size(); i++){
			if(nums[i] != prev){
				nums[k++] = nums[i];
				prev = nums[i];
			}
		}
        return k;
    }
};

=============================================================================

80 remove duplicated from sorted arrayII(将数组中元素出现超过两次的次数移除)

Follow up for "Remove Duplicates":
What if duplicates are allowed at most twice?

For example,
Given sorted array nums = [1,1,1,2,2,3],

Your function should return length = 5, with the first five elements of nums being 1122 and 3. It doesn't matter what you leave beyond the new length.

思路改动:与26题相比,新数组中元素可以出现的次数,由一次变为两次。

class Solution {
public:
	int removeDuplicates(vector<int>& nums) {
        int k = 0;
		int count = 0;
		if(nums.size() == 0) return 0;
		int prev = nums[0];
		nums[k++] = nums[0];
		for(int i = 1; i < nums.size(); i++){
			if(nums[i] != prev){
				nums[k++] = nums[i];
				prev = nums[i];
				count = 0;
			}
            else if(count == 0){
				nums[k++] = nums[i];
				prev = nums[i];
				count = 1;
			}
		}
        return k;
    }
};


总结:可以看到,上面几道题的解决思路都是一样的。即,通过定义新的索引,来保存筛选后的元素。


二.利用基础算法

75 sort colours(对只有0,1,2的数组进行排序)

Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the 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 for this problem.

思路:利用计数排序(适用于数组中元素类型有限)或者三路快排。

class Solution {
public:
	//计数排序
	/*
    void sortColors(vector<int>& nums) {
        int counts[3] = {0};
        for(int i=0; i<nums.size(); i++){
			if(nums[i]==0) counts[0]++;
			if(nums[i]==1) counts[1]++;
			if(nums[i]==2) counts[2]++;
		}
		int index=0;
		for(int i=0; i<sizeof(counts)/sizeof(counts[0]); i++){
			for(int j=0; j<counts[i]; j++)
				nums[index++]=i;
		}
    }*/
	//三路快排
	void sortColors(vector<int>& nums) {
        int zero = -1; //nums[0...zero] == 0
		int two = nums.size(); //nums[two...n-1] == 2
		for(int i=0; i<two; ){
			if(nums[i]==1) i++;
			else if(nums[i]==2){
				two--;
				swap(nums[i], nums[two]);
			}
			else{
				assert(nums[i]==0);
				zero++;
				swap(nums[zero], nums[i]);
				i++;
			}
		}
    }
};



=============================================================================

88 Merge Sorted Array(将nums2的数组合并到nums1中)

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.

思路:利用归并排序。

tips:归并排序:将数组分成两组A,B,如果这两组组内的数据都是有序的,那么就可以很方便的将这两组数据进行排序。

如何让这两组组内数据有序?

可以将A,B组各自再分为两组。依次类推,当分出来的小组只有一个数组时,可以认为这个小组组内已经达到了有序。

然后再合并相邻的两个小组就可以了。这样,通过先递归来分解数列,再合并数列,就完成了归并排序。

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i = m - 1, j = n - 1;
        int t = m + n -1;
        while(i >= 0 && j >= 0)
        {
            if(nums1[i] > nums2[j])
                nums1[t--] = nums1[i--];
            else
                nums1[t--] = nums2[j--];
        }
        while(i >= 0)
        {
            
            nums1[t--] = nums1[i--];
        }
        while(j >= 0)
        {
            nums1[t--] = nums2[j--];
        }
    }
};


=============================================================================

215 kth largest element in an array(找到数组中第k大的元素)

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.

思路:可利用一般排序算法解决,这里利用快速排序。

//快速排序
class Solution {
public:
    void quickSort(vector<int>& nums, int left, int right){
        if(left > right) return;
		int i = left, j = right, temp = nums[left];
		while(i < j){
			while(nums[j]>=temp && i < j){
				j--;
			}
			while(nums[i]<=temp && i < j){
				i++;
			}
			if(i<j) swap(nums[i],nums[j]);
		}
		swap(nums[i],nums[left]);
		quickSort(nums, left, i-1);
		quickSort(nums, i+1, right);
	}
    int findKthLargest(vector<int>& nums, int k) {
        quickSort(nums, 0, nums.size()-1);
		return nums[nums.size()-k];
    }
};

总结:对于一些基本的排序问题,可以利用基本排序思路来解决。


三.对撞指针

167 two sum ii -input array is sorted (在排序数组中,找到和为sum的两个元素,返回索引。)

Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution and you may not use the same element twice.

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

返回索引

1.如果没有解怎样?保证有解

2.如果有多个解怎样?返回任意解

思路:定义两个索引,分别从数组的起点和终点出发。如果两个索引指向的元素的和<sum,则左边索引+1;如果两个索引指向的元素的和>sum,则右边索引-1。充分利用了数组是有序的这一给定条件。

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int l = 0, r = numbers.size() - 1;
        while(l < r) //l与r不能指向同一个元素
        {
            if(numbers[l] + numbers[r] == target){
				int res[2] = {l+1, r+1};
				return vector<int>(res, res+2);
			}
			else if(numbers[l] + numbers[r] < target){
				l++;
			}
			else if(numbers[l] + numbers[r] > target){
				r--;
			}
        }

		throw invalid_argument("The input has no solution.");
    }
};

如果数组无序,该怎么解决呢?

可以利用map进行解决。

1Two Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> m;
        vector<int> res;
        for(int i = 0; i < nums.size(); i++){
            if(m.find(target-nums[i]) != m.end()){
                int res[2] = {i, m[target-nums[i]]};
                return vector<int>(res, res+2);
            }else{
                m[nums[i]] = i;
            }
        }
        return res;
    }
};

=============================================================================

125 valid palindrome(判断字符串是否是回文串)

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.

For example,
"A man, a plan, a canal: Panama" is a palindrome.
"race a car" is not a palindrome.

Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.

For the purpose of this problem, we define empty string as valid palindrome.字符串问题:

思考细节:空字符串如何看?

1.字符的定义?

2.大小写问题?

思路:同样,也可以定义两个索引,分别从字符串的起点和终点出发。过滤掉非字母数字,判断指针所在的位置,两个元素是否相等。

tip:在过滤的时候,指针移动,需要注意,左指针的索引不能超过右指针。

class Solution {
public:
    bool isPalindrome(string s) {
        int i = 0, j = s.length()-1;
        while(i<j){
             while(isalnum(s[i]) == false && i<j){
                i++;
            } 
            while(isalnum(s[j]) == false && i<j){
                j--;
            }
            if(toupper(s[i]) != toupper(s[j])) return false;
          
            i++;
            j--;
            
        }
        return true;
    }
};


=============================================================================

344 reverse string

Write a function that takes a string as input and returns the string reversed.

Example:
Given s = "hello", return "olleh".

思路:同样,也可以定义两个索引,分别从字符串的起点和终点出发,交换彼此所在位置的元素。

class Solution {
public:
    string reverseString(string s) {
        int i = 0, j = s.length()-1;
        while(i<j)
        {
            swap(s[i],s[j]);
            i++;
            j--;
        }
        return s;
    }
};

=============================================================================


345 reverse vowels of string (对字符串的元音字母进行翻转,辅音不变)

Write a function that takes a string as input and reverse only the vowels of a string.

Example 1:
Given s = "hello", return "holle".

Example 2:
Given s = "leetcode", return "leotcede".

Note:
The vowels does not include the letter "y".

思路改进:过滤掉非元音元素。

class Solution {
public:
    string reverseVowels(string s) {
        int i = 0, j = s.length()-1;
        while(i < j){
            while((s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u' || s[i] == 'A' || s[i] == 'E' || s[i] == 'I' || s[i] == 'O' || s[i] == 'U') && (s[j] == 'a' || s[j] == 'e' || s[j] == 'i' || s[j] == 'o' || s[j] == 'u' || s[j] == 'A' || s[j] == 'E' || s[j] == 'I' || s[j] == 'O' || s[j] == 'U') && i < j){
                swap(s[i],s[j]);
                i++;
                j--;
            }
           
             while((s[i] != 'a' && s[i] != 'e' && s[i] != 'i' && s[i] != 'o' && s[i] != 'u' && s[i] != 'A' && s[i] != 'E' && s[i] != 'I' && s[i] != 'O' && s[i] != 'U') && i < j){
                i++;
            }
            
             while((s[j] != 'a' && s[j] != 'e' && s[j] != 'i' && s[j] != 'o' && s[j] != 'u' && s[j] != 'A' && s[j] != 'E' && s[j] != 'I' && s[j] != 'O' && s[j] != 'U') && i < j){
                j--;
            }
            
        }
        return s;
    }
};


=============================================================================

11 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 and n is at least 2.

思路:由于该数组是无序的,两个索引向内移动,会导致”容器“宽度降低。那么,向内移动的条件就只能是内部的元素大于外部的元素。

class Solution {
public:
    int maxArea(vector<int>& height) {
        int i = 0, j = height.size()-1;
        int water = -1;
        while(i < j){
            int h = min(height[i], height[j]);
            water = max(water, (j-i) * min(height[i], height[j]));
            while(height[i] <= h && i < j) i++;
            while(height[j] <= h && i < j) j--;
        }
        return water;
    }
};

总结:当问题可以简化为对数组中的两个元素进行操作的时候,可以尝试使用对撞指针的方法。


四.滑动窗口

滑动窗口需要考虑的关键:初始信息,以及窗口滑动的条件 : 子窗口尚未满足条件,子窗口向右扩展;子窗口已满足条件,子窗口向左推移。

209 minimum size subarray sum(找到满足元素和>=s的最小连续子数组)

Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.

For example, given the array [2,3,1,2,4,3] and s = 7,
the subarray [4,3] has the minimal length under the problem constraint.

思考细节:

1.什么叫子数组,连续子数组

2.如果没有解怎么办,返回0

思路:定义滑动窗口,去匹配相应的连续子数组。

//时间复杂度:o(n)
//空间复杂度:o(1)
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int l = 0, r = -1; //nums[1...r]为我们的滑动窗口
		int sum = 0;
		int res = nums.size() + 1;//最小值一定小于nums.size()+1

		//滑动窗口左边可以取值,右边也可以取值。
		while(l < nums.size())
		{
			if(r+1 < nums.size() && sum < s){
				r++;
				sum += nums[r];
			}else{
				//如果sum>=s,那么可以减小窗口的大小。
				sums -= nums[l];
				l++;
			}

			if(sum >= s)
				res = min(res, r-l+1);
		}

		if(res == nums.size() + 1) return 0;
		return res;
    }
};



=============================================================================

3longest substring without repeating characters(找到没有重复字符的最长子串)

Given a string, find the length of the longest substring without repeating characters.

Examples:

Given "abcabcbb", the answer is "abc", which the length is 3.

Given "bbbbb", the answer is "b", with the length of 1.

Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring"pwke" is a subsequence and not a substring.

思考细节:寻找没有重复字母的最长子串

1.字符集?只有字母?数字+字母?ascii?

2.大小写是否敏感?

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int freq[256] = {0};
		int l = 0, r = -1;//滑动窗口为s[l,r]
		int res = 0;
		while(l < s.size()){
			if(r+1<s.size() && freq[s[r+1]]==0){
				r++;
				freq[s[r]]++;
			}else{
				freq[s[l]]--;
				l++;
			}
			res = max(res, r-l+1);
		}

		return res;
    }
};

tip:

C++数组的下标可以是字符的。解释如下:

  1. C++中字符在计算机内存储的是字符的ASCII码;

  2. 而ASCII码实质是数字,例如‘a’是97,‘A'是65;

  3. 如果用字符作为下标,实质就是用该字符的ASCII码作为下标;

  4. 但是在用字符作为下标时没有数字直观,容易引起数组越界,因此不建议这样用。


=============================================================================

438 find all anagrams in a string

Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.

Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.

The order of output does not matter.

Example 1:

Input:
s: "cbaebabacd" p: "abc"

Output:
[0, 6]

Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".

Example 2:

Input:
s: "abab" p: "ab"

Output:
[0, 1, 2]

Explanation:
The substring with start index = 0 is "ab", which is an anagram of "ab".
The substring with start index = 1 is "ba", which is an anagram of "ab".
The substring with start index = 2 is "ab", which is an anagram of "ab".

思考细节:anagrams:两个字符串包含的字母是相同的,则会互为anagrams。

1.字符集范围?英文小写字母

2.返回的解的顺序?任意

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int l = 0, r = -1;
        int head = l, count = p.size();
        int n = s.size();
        vector<int> map(128, 0);
        vector<int> res;
        for(auto c:p) map[c]++;
        while(l < n){
            if(r+1<n && count>0){
                r++;
                if(map[s[r]] > 0){
                    count = count-1;
                }
                map[s[r]]--;
                
            }else{
                if(map[s[l]] == 0){
                    count = count+1;
                }
                map[s[l]]++;
                l++;
            }
            if(count == 0){
                if(p.size() == r-l+1){
                    res.push_back(l);
                }
            }
        }
        return res;
    }
};

=============================================================================

76 minimum window substring

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example,
S = "ADOBECODEBANC"
T = "ABC"

Minimum window is "BANC".

Note:
If there is no such window in S that covers all characters in T, return the empty string "".

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

思路:用滑动窗口对字符串s进行滑动,如果找到了一个p中的元素,则”寻找指标“-1。

class Solution {
public:
    string minWindow(string s, string t) {
        int l = 0, r = -1;
        int head = l, count = t.size(), n = s.size();
        int res = n + 1;
        if(count > n) return "";
        vector<int> map(128, 0);
        for(auto c:t) map[c]++;
        while(l < n){
            if(r+1 < n && count > 0){
                r++;
                if(map[s[r]] > 0){
                    count = count - 1;
                }
                map[s[r]]--;
                
            }else{
                if(map[s[l]] == 0){
                    count = count + 1;
                }
                map[s[l]]++;
                l++;
            }
            if(count == 0){
                if(res > r - l + 1){
                    head=l;
                    res = min(res, r - l + 1);
                }  
            }
        }
        if(res == n + 1) return "";
        return s.substr(head, res);
    }
};
总结:对于连续子数组问题,可以尝试用滑动窗口法解决。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Solidity中的数组是一种用于存储相同类型数据的数据结构。数组可以是固定大小的,也可以是动态大小的。固定大小的数组在声明时需要指定数组的大小,并且元素的总数不应超过数组的大小。Solidity中的数组是一种用于存储相同类型数据的数据结构。数组可以是固定大小的,也可以是动态大小的。固定大小的数组在声明时需要指定数组的大小,并且元素的总数不应超过数组的大小。而动态数组的大小在声明时没有预定义,随着元素的添加,数组的大小会发生变化,并且在运行时,数组的大小将被确定。Solidity中的数组是一种用于存储相同类型数据的数据结构。数组可以是固定大小的,也可以是动态大小的。固定大小的数组在声明时需要指定数组的大小,并且元素的总数不应超过数组的大小。而动态数组的大小在声明时没有预定义,随着元素的添加,数组的大小会发生变化,并且在运行时,数组的大小将被确定。在Solidity中声明数组时,需要指定元素的数据类型和元素的数量。数组的大小必须是正整数并且数据类型应该是有效的Solidity类型。以下是一些Solidity数组的示例: 1. 固定大小的数组声明:uint myArray; 2. 固定大小的数组初始化:uint myArray = [1, 2, 3, 4, 5]; 3. 动态数组声明:uint[] myArray; 4. 动态数组初始化:uint[] myArray = [1, 2, 3]; 5. 动态数组添加元素:myArray.push(4); 6. 访问数组元素:myArray;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值