初级算法——数组

这篇博客探讨了数组在算法中的应用,包括删除排序数组中的重复项(使用双指针)、买卖股票的最佳时机(贪心算法与动态规划)、旋转数组(翻转法)、查找重复元素(排序与set容器)、只出现一次的数字(位运算解法)、两数组的交集(双指针与map计数)、加一操作、移动零(双指针交换)、两数之和(哈希表)、有效数独(计数验证)以及旋转图像(翻转法)。通过这些实例,介绍了多种解决问题的思路和技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、数组

1.删除排序数组中的重复项(双指针):

(1)审题不清,效率不高

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        auto it = nums.begin();
        while (it != nums.end() - 1)
        {
            if (*it == *(it + 1))
            {
                it = nums.erase(it);
            }
            else
            {
                ++it;
            }
        }
        return nums.size();
    }
};

(2)

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

2.买卖股票的最佳时机II

(1)贪心算法

因为没有限制买卖的次数,所以我们可以理解为相邻两天的利润和

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1)return 0;
        int profit = 0;
        for (int i = 1; i < prices.size(); ++i)
        {
            if (prices[i] > prices[i - 1])
            {
                profit += (prices[i] - prices[i - 1]);
            }
        }
        return profit;
    }
};

(2)动态规划

定义一个二维数组dp表示这一天结束后的最大利润,dp[i][0]表示这一天结束手中没有股票,这可能是前一天结束后手中就没有股票,或者这一天结束后股票已经卖出;dp[i][1]表示这一天结束手中有股票,这也可能是前一天结束后手中的股票,今天没有购入,或者昨天结束后没有股票,今天买入了。

最后,如果要获得最大利润那就说明最后一天结束后手中是没有股票的。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>>dp(len, vector<int>(2, 0));
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        for (int i = 1; i < len; ++i)
        {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        }
        return dp[len - 1][0];
    }
};

3.旋转数组

(1)使用临时数组

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        auto temp = nums;
        int len = nums.size();
        for (int i = 0; i < len; ++i)
        {
            nums[(i + k) % len] = temp[i];
        }
    }
};

(2)翻转法

第一步先翻转所有元素

第二步翻转前k个元素

第三步翻转后面的元素

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int len = nums.size();
        k %= len;
        reverse(nums, 0, len - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, len - 1);
    }
    void reverse(vector<int>v, int start, int end)
    {
        while (start < end)
        {
            auto temp = v[start];
            v[start++] = v[end];
            v[end--] = temp;
        }
    }
};

4.存在重复元素

(1)使用了算法sort对数组进行排序,然后在比较相邻的两个元素

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        for (int i = 1; i < nums.size(); ++i)
        {
            if (nums[i] == nums[i - 1])
            {
                return true;
            }
        }
        return false;
    }
};

(2)使用set容器

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        set<int>un;
        for (auto m : nums)
        {
            if (un.find(m) != un.cend())
            {
                return true;
            }
            un.insert(m);
        }
        return false;
    }
};

5.只出现一次的数字

(1)使用位运算

使用异或运算,将所有值进行异或
异或运算,相异为真,相同为假,所以 a^a = 0 ;0^a = a
因为异或运算 满足交换律 a^b^a = a^a^b = b 所以数组经过异或运算,单独的值就剩下了

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int temp = 0;
        for (auto n : nums)
        {
            temp = temp ^ n;
        }
        return temp;
    }
};

6.两个数组的交集II

(1)双指针

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        sort(nums1.begin(), nums1.end());
        sort(nums2.begin(), nums2.end());
        int i = 0, j = 0;
        vector<int>temp;
        while (i < nums1.size() && j < nums2.size())
        {
            if (nums1[i] > nums2[j])
            {
                ++j;
            }
            else if (nums1[i] < nums2[j])
            {
                ++i;
            }
            else
            {
                temp.push_back(nums1[i]);
                ++i;
                ++j;
            }
        }
        return temp;
    }
};

(2)利用map计数

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        if (nums1.size() > nums2.size())return intersect(nums2, nums1);
        map<int, int>m;
        vector<int>temp;
        for (auto n : nums1)m[n]++;
        for (auto n : nums2)
        {
            if (m.count(n))
            {
                m[n]--;
                temp.push_back(n);
                if (m[n] == 0)
                {
                    m.erase(n);
                }
            }
        }
        return temp;
    }
};

7.加一

判断每一位是否为9,如果不为9直接加1;

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        int len = digits.size();
        for (int i = len - 1; i >= 0; --i)
        {
            if (digits[i] != 9)
            {
                digits[i]++;
                return digits;
            }
            else
            digits[i] = 0;
        }
        digits.insert(digits.begin(), 1);
        return digits;
    }
};

8.移动零

(1)双指针

把非0的往前挪

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

(2)双指针

交换

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int index = 0, i = 0;
        while (i < nums.size())
        {
            if (nums[i])
            {
                swap(nums[index], nums[i]);
                index++;
            }
            i++;
        }
    }
};

9.两数之和

(1)暴力for循环

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int len = nums.size();
        for (int i = 0; i < len - 1; i++)
        {
            for (int j = i + 1; j < len; j++)
            {
                if (nums[i] + nums[j] == target)
                {
                    return {i, j};
                }
            }
        }
        return {};
    }
};

(2)哈希表

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int>hashtable;
        for (int i = 0; i < nums.size(); ++i)
        {
            auto it = hashtable.find(target - nums[i]);
            if (it != hashtable.end())
            {
                return { it->second,i };
            }
            hashtable.insert(make_pair(nums[i],i));
        }
        return {};
    }
};

10.有效的数独

创建两个二维数组和一个三维数组表示行、列和3x3区域数字的出现次数,并初始化。

遍历整个表格。

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int row[9][9];
        int column[9][9];
        int cell[3][3][9];
        memset(row, 0, sizeof(row));
        memset(column, 0, sizeof(column));
        memset(cell, 0, sizeof(cell));
        for (int i = 0; i < 9; ++i)
        {
            for (int j = 0; j < 9; ++j)
            {
                if (board[i][j] != '.')
                {
                    int num = board[i][j] - '1';
                    row[i][num]++;
                    column[j][num]++;
                    cell[i / 3][j / 3][num]++;
                    if (row[i][num] > 1 || column[j][num] > 1 || cell[i / 3][j / 3][num] > 1)
                        return false;
                }

            }
        }
        return true;
    }
};

11.旋转图像

(1)用翻转代替旋转

首先上下翻转再关于对角线翻转

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        for (int i = 0; i < n / 2; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                swap(matrix[i][j], matrix[n - i - 1][j]);
            }
        }
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                swap(matrix[i][j], matrix[j][i]);
            }
        }
    }
};

(2)直接交换

因为是对称的,所以只要旋转前半部分就可以了

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int len = matrix.size();
        for (int i = 0; i < len / 2; i++)
        {
            for (int j = i; j < len - i - 1; ++j)
            {
                int m = len - i - 1;
                int n = len - j - 1;
                auto temp = matrix[i][j];
                matrix[i][j] = matrix[n][i];
                matrix[n][i] = matrix[m][n];
                matrix[m][n] = matrix[j][m];
                matrix[j][m] = temp;
            }
        }
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值