大家好,我是怒码少年小码。
😎今天开始新的篇章——数组。
数组的常见问题
1. 数组初始化的本质是什么?
答:覆盖。你可以只搞前面几个,如:[1,2,3,0,0,0,0]
2. 上面已初始化的元素之间是否可以空着?例如:[1,0,2,0,0,3,0]
答:不可以!绝对不可以😠!必须从前向后连续空间初始化,不可以出现空缺的情况。在某种运行期间可以只是部分赋值,但是稳定下来之后,就不可以出现空着的情况。
3. 如果我需要的数据就是在中间某一段怎么办?例如[0,0,0,1,2,3,4,0,0],此时怎么拿到元素?
答:使用两个变量,例如left=3,right=6
来表示区间[left,right]是有效的。
4. [1,2,3,4,0,0],删除3之后[1,2,4,?,0,0],?上是啥?
答:还是4。数组删除的本质是移动和覆盖。
数组的增删改查
查找一个元素
int findByElement(int arr[], int size, int key) {
for (int i = 0; i < size; i++) {
if (arr[i] == key) {
return i;
}
}
return -1;
}
增加一个元素
说实话,看着简单,但是要自己完全写出来还是要费一点时间。
int* addByElement(int arr[], int key, int size) {
int newSize = size + 1;
int* newArr = new int[newSize];
for (int i = 0; i < size; i++) {
newArr[i] = arr[i];
}
newArr[size] = key;
return newArr;
}
删除一个元素
前面也提到了,删除的本质就是移动后面的元素覆盖前面的元素。
//删除一个元素
int removeByElement(int arr[], int size, int key) {
int index = -1;
//找到要删除元素的位置并保存
for (int i = 0; i < size; i++) {
if (arr[i] == key) {
index = i;
break;
}
}
if (index != -1) {
//移动元素
for (int j = index + 1; j < size; j++) {
arr[j - 1] = arr[j];
}
//更新数组大小
size--;
}
//输出检查
for (int i = 0; i < size; i++) {
cout << arr[i] << endl;
}
return size;
}
算法热身
1.数组单调问题
这是LeetCode 896😎,判断一个数组是否为单调数组。
1.1 方法一
因为单调分为单增和单减两种情况,所以我们可以先定义一个函数判断是否为单增或单减,再定义另外一共函数判断是否符合其一。
bool isSorted(int arr[],int size,bool increasing) {
for (int i = 0; i < size - 1; i++) {
if (increasing) {
if (arr[i] >= arr[i + 1]) {
return false;
}
}
else {
if (arr[i] <= arr[i + 1]) {
return false;
}
}
}
return true;
}
根据你传来的increaing
判断,如果是true
,则是判断是否为单增;如果是false
,则是判断是否为单减。
bool isMonotony(int arr[], int size) {
//两种情况:单增和单减
if (isSorted(arr, size, true) || isSorted(arr, size, false)) {
cout << "单调" << endl;
return true;
}
else {
cout << "不单调" << endl;
return false;
}
}
分成单增和单减的实在是太麻烦了,有没有更好的方法呢🤔?答案是肯定滴~
1.2 方法二(优化升级)
来,放轻松~观察一下,单调性有什么特点?是不是链表只要有任意连续的两个元素的单调性和其他的元素的单调性不同,那么这个数组就不具有单调性。
所以我们可以用两个变量来保存数组中的单增存在情况inc
和单减存在情况dec
bool isMonotony01(int arr[], int size) {
bool inc = true;
bool dec = true;
for (int i = 0; i < size - 1; i++) {
if (arr[i] > arr[i + 1]) {
inc = false;
}
if (arr[i] < arr[i + 1]) {
dec = false;
}
}
if (inc || dec) {
cout << "单调" << endl;
return true;
}
else {
cout << "不单调" << endl;
return false;
}
return inc || dec;
}
inc
和dec
初始化为true
,当然在遍历中只用当数组中既有单增的部分又有单减的部分时,inc
和dec
都为false
,这时inc || dec
为false
。(这真的妙啊~)
不知道大家什么心情,我是真的有点破防了🥲,辛辛苦苦好不容易用写出第一种,理顺了思路,结果你和我说有个更好的呜呜。我怎么之前没想到呀,果然人外有人,天外有天🫡,还是得多练。
2. 数组合并
LeetCode 88:合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
示例:
- 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
- 输出:[1,2,2,3,5,6]
这个题目有一个特点就是nums1它已经帮你把位置空出来了,所以我们何不从后面开始遍历~
void mergeArray(int nums1[], int nums1_len,int m, int nums2[], int nums2_len,int n) {
int i = m + n - 1;
int len1 = m - 1;
int len2 = n - 1;
while (len1 >= 0 && len2 >= 0) {
if (nums1[len1] <= nums2[len2]) {
nums1[i--] = nums2[len2--];
}
else {
nums1[i--] = nums1[len1--];
}
}
//还有数组中有剩余
while (len2 != -1) {
nums1[i--] = nums2[len2--];
}
while (len1 != -1) {
nums1[i--] = nums1[len1--];
}
for (int j = 0; j < m + n; j++) {
cout << nums1[j] << ",";
}
cout << endl;
}