算法设计与应用基础(一)

开此专题,记录《算法设计与应用基础》课程所做的题目,大部分来源于Leetcode。

1、(sort)Insert Interval

题目描述:Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). You may assume that the intervals were initially sorted according to their start times.

Example 1:

Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]

Example 2:

Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].

 思路:遍历输入的数组,将每个元素(curInterval)与newInterval比较,分类讨论,确定要往保存答案的数组(answer)中加入哪一个Interval或者需要对newInterval做变换。

(1)curInterval.end < newInterval.start: 说明curInterval可以加入answer

(2)curInterval.start > newInterval.end: 说明newInterval可以加入answer,然后把输入数组中余下的元素加入answer

(3)其他情况则说明newInterval和curInterval有重叠部分,我们把newInterval和curInterval合并为一个新的newInterval,然后再和往下其他元素比较。

其实也可以说是把在输入数组上滑动newInterval,检查是否有重叠。

class Solution
{
  public:
    vector<Interval> insert(vector<Interval> &intervals, Interval newInterval)
    {
        vector<Interval> ans;
        for(int i=0;i<intervals.size();++i)
        {
            if(newInterval.start>intervals[i].end)
                ans.push_back(intervals[i]);
            else if(newInterval.end<intervals[i].start)
            {
                ans.push_back(newInterval);
                for(int j=i+1;j<intervals.size();++j)
                    ans.push_back(intervals[j]);
                return ans;
            }
            else
            {
                int newstart = min(newInterval.start,intervals[i].start);
                int newend = max(newInterval.end,intervals[i].end);
                newInterval = Interval(newstart,newend);
            }
        }
        ans.push_back(newInterval);
        return ans;
    }

};

 2、(sort)Search a 2D Matrix

题目描述:

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

 

  • Integers in each row are sorted in ascending from left to right.
  • Integers in each column are sorted in ascending from top to bottom.

For example, consider the following matrix:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

Given target = 5, return true。

Given target = 20, return false.

题目既然明确说了输入的矩阵的特点,那就必然不是O(n*m)的时间复杂度。一开始我往lgn方向想,自然地想到用二分查找,但发现其实也没完全利用到该矩阵的特点,后来学习了Leetcode上Discuss区其他人的解法:

从左下角的元素(row = n, col = 1)开始与目标元素比较,如果元素大于目标元素,则row-1,继续比较,因为根据特点,row=n且1<col<=m的元素肯定也大于目标元素;而如果元素小于目标元素,则col+1,继续比较,因为根据特点,1<=row<n且col=1的元素肯定也小于目标元素,而row=n且1<col<=m的元素则大于目标元素。按此思路寻找目标元素直到找到或者查找范围超出了矩阵的边界。

class Solution
{
  public:
    void sortColors(vector<int> &nums)
    {
        int low = 0, mid = 0, high = nums.size() - 1;
        while (mid <= high)
        {
            if (nums[mid] == 0)
            {
                int t = nums[mid];
                nums[mid] = nums[low];
                nums[low] = t;
                low++, mid++;
            }
            else if (nums[mid] == 1)
                mid++;
            else
            {
                int t = nums[mid];
                nums[mid] = nums[high];
                nums[high] = t;
                high--;
            }
        }
    }
};

3、(sort)Kth Largest Element in an Array 

题目描述:给定一个未排序的整型数组,有 n(2≤n≤105) 个元素,求第 k 大的元素。(请不要使用库函数排序)

例1: nums = [3, 2, 1, 5, 6, 4], k = 2, 函数返回 5.

例2: nums = [3, 2, 3, 1, 2, 4, 5, 5, 6], k=4, 函数返回 4.

思路:虽然STL中有写好的函数可以直接用,但我们还是要知道如果不用库函数(O(N))可以怎么比较有效地求解。这题我用了优先队列(内部实现为堆)辅助求解。采用堆顶元素为队列中所有元素最小值的优先队列。

遍历输入数组,把数组元素加入到队列中。若当前队列的大小为K,则判断当前遍历到的元素是否大于或者等于堆顶元素,是的话则将堆顶元素出队然后把当前元素入队。最后数组的第K大元素就是最终优先队列的堆顶元素。因为我们每次堆顶元素都是当前队列中最小的元素,而如果我们遍历到的元素大于堆顶元素我们就将堆顶元素出队然后将当前元素入队,实际上就是把较大的数放进队列中,所以最后没能入队的或者入队后又出队的元素,都是比队列中那K个元素都小的,所以堆顶元素就是第K大了。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int,vector<int>,greater<int> > pq;
        pq.push(nums[0]);
        int n = nums.size();
        for(int i=1;i<n;++i)
        {
            int num = nums[i];
            if(pq.size()==k)
            {
                if(pq.top()>num)
                    continue;
                pq.pop();
            }
            pq.push(num);
        }
        return pq.top();
    }
};

4、(sort) Largest Number

题目描述:给定一个由 n(2≤n≤105)n(2≤n≤105) 个非负整数组成的数组 numsnums,要求对 numsnums 中的元素进行安排,使其形成的数最大。

一开始我是想对输入数组中的每个整数排序,排序的依据是每次从最高位到最低位比较要排序的两个元素来决定哪一个元素在前哪一个在后,但发现其实还有其他要考虑的地方,觉得肯定没这么麻烦。然后看了Discuss区别人的解法:

因为结果返回的是字符串,所以直接先把所有整数转为字符串。我们要的是对各数字排序使得最后组成的元素最大,其实也就是考虑对这些数字排序的时候,哪个在前哪个在后会使得最后形成的数字最大,所以在排序时我们只要以num_str1+num_str2>num_str2+num_str1来判断两个字符串前后的位置即可。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int,vector<int>,greater<int> > pq;
        pq.push(nums[0]);
        int n = nums.size();
        for(int i=1;i<n;++i)
        {
            int num = nums[i];
            if(pq.size()==k)
            {
                if(pq.top()>num)
                    continue;
                pq.pop();
            }
            pq.push(num);
        }
        return pq.top();
    }
};

5、(sort)Sort Colors

题目描述:

Given an array with n objects colored red, white or blue, sort them in-place(the input is overwritten by the output as the algorithm executes) 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.

Example:

Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

 这题要求O(N)且一次遍历的解法,我愚钝,一时想不出符合这种要求的算法,我也忘了我是看Solution还是Discuss的。

因为只有三种颜色,而0如果存在则一定是排在左边,2如果存在则一定是排在右边。所以我们设置一个索引指向数组的最左边(low,有序数组中的最后一个0),一个索引指向数组的最右边(high,有序数组中的第一个2),再设置一个索引执行当前遍历到的元素的下标(mid)。然后每次遍历到一个元素,如果该元素为0,则交换mid和low的元素,把0移到左边,然后low和mid都右移一位(low++,mid++);如果该元素为1,则仅将mid右移一位,因为有序的数组中1处于中间;如果该元素为2,则交换mid和high,然后右移mid,左移high。按此规则遍历元素,知道索引mid>high。因为high指向的是有序数组中的第一个2.

 

class Solution
{
  public:
    void sortColors(vector<int> &nums)
    {
        int low = 0, mid = 0, high = nums.size() - 1;
        while (mid <= high)
        {
            if (nums[mid] == 0)
            {
                int t = nums[mid];
                nums[mid] = nums[low];
                nums[low] = t;
                low++, mid++;
            }
            else if (nums[mid] == 1)
                mid++;
            else
            {
                int t = nums[mid];
                nums[mid] = nums[high];
                nums[high] = t;
                high--;
            }
        }
    }
};

最后一题的解法其实是一类解法:要提高时间效率,可以设置多个指向数组特定位置的“指针”,这些指针有特定的含义,这样或许能过设计出只遍历一次数组的线性时间复杂度的解法。 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值