leetcode 刷题日记 week1-4

week1

2020.3.8 - 2020.3.15

26

27

41

55

dp, dp[i] = max(dp[i-1],nums[i-1])-1 表示最远能到达的地方
return dp.back()<=0 (可以随时返回false节省时间)

80

118

119

134

169

189

283

299

442

448

week2:

2020.3.15 - 2020.3.21

11

35

56

先排序,再遍历的同时合并

57

由于intervals 是有序的,遍历即可, O(N)

75

88

153

162

164

217

278

289:

涉及到位置间的相互影响,使用余数记录变化,同时保留原本信息
in-place
使用2代表0->1
使用3代表1->0

327 hard

1.区间和的问题要计算累计数组和sums[i]
2.使用multiset: lower_bound, upper_bound set允许重复的元素
multiset.insert(XXX)
3.STL distance(iterator1, iterator2)
4.关注数字的范围,求和可能超范围。

对于某个i来说,只有那些满足 lower <= sum[i] - sum[j] <= upper 的j能形成一个区间 [j, i] 满足题意,目标就是来找到有多少个这样的 j (0 =< j < i) 满足 sum[i] - upper =< sum[j] <= sum[i] - lower


image.png

376

week 3:

2020.3.22 - 2020.3.29

42

智力趣味题,更多解法参考:https://www.cnblogs.com/logosg/p/7979690.html
双指针法: 比较 左 右指针的高度大小,若左边大,则右边只需要关注右侧能否蓄水(因为左侧一定可以支撑住);反之亦然
单调栈法:https://www.cnblogs.com/grandyang/p/8887985.html

  • 单调递增栈可以找到左起第一个比当前数字小的元素
  • 单调递减栈可以找到左起第一个比当前数字大的元素

使用递减单调栈,因为当有更小的数来,直接入栈;有更大的数来,说明可以处理存水的体积了。
计算水的体积会把空隙进行横向分层。

stack存的是index而不是高度。

每一次的处理:
每次取top,pop,然后如果左面没有top,说明只有一边,无法蓄水,break。
如果昨天top高度和当前高度相同,则continue
计算高度,width(两边柱子距离-1)和height(木桶短板-底部),加到结果里去。

class Solution {
public:
    int trap(vector& height) {
        if(height.empty()) return 0;
        height.push_back(0);
        int res =0;
        stack st;//decreasing stack
        for(int i = 0; i height[st.top()]){
                int top  =st.top();
                st.pop();
                if(st.empty()) break;
                if(height[top] ==height[st.top()]) continue;
                int width = i-st.top()-1;
                int h = min(height[st.top()],height[i]);
                res += width*(h-height[top]);
            }
            st.push(i);
        }
        return res;
    }
};

81

反复调试的解法: 可退化,4ms
若left,right值相等,则遍历(退化为O(n))
若【left】<【right】,则正序,正常二分查找 mid=(left+right+1/2
若【left】》【right】,则为逆序,若【target】>=【left】则在左半边,否则右半边
踩过的坑:

  • 谨防陷入死循环,设定一个若mid和上次相同,直接判断
  • 原本写了在正序时if(target

待学习:不退化,1ms

public class Solution {
    public boolean search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (target == nums[mid]) return true;
            if (nums[mid] == nums[left]) left++;
            else if (nums[mid] > nums[left]) {
                if (nums[left] <= target && nums[mid] > target) right = mid - 1;
                else left = mid + 1;
            } else {
                if (nums[mid] < target && target <= nums[right]) left = mid + 1;
                else right = mid - 1;
            }
        }
        return false;
    }
}

128

  • 要求O(n)时,可以想使用哈希表

152

容易想到动态规划,但是负数和0的存在比较麻烦,如[5,-2,-3];
可以设计两个数组,dp_max = max{nums[i], nums[i]dp_max[i-1], nums[i]dp_min[i-1]}, dp_min = min{nums[i], nums[i]dp_max[i-1], nums[i]dp_min[i-1]}。
返回dp_max中的最大值。

209

失败尝试:看到O(nlogn)想到二分查找,可以通过一部分用例但会卡在一部分上。使用sum数组,假设,j遍历,i使用二分查找到sum[j]-sum[i]>=s 的最小的j-i
注意:特殊输入的测试用例
博客学习:双指针,right遍历,left向右滑,但未理解如何计算为O(n)的复杂度
未解决:学会O(nlogn)的算法

228

遍历一次即可,注意处理末尾的情况。

238

使用两个数组。每一位等于前面数的乘积乘后面数的乘积

239

学习:使用双向队列,当列中的back比当前值小,全部pop;若列中的back比当前值大,push 当前值。 同时,超出滑窗范围的也需要从front中去掉。
待解决:其他方法
deque:
最好采用deque的情形:
1、需要在两端插入和删除元素。
2、无需引用容器内的元素。
3、要求容器释放不再使用的元素。

image.png

image.png

image.png

287

博客学习:双指针方法,由于数字的范围都在1-n之间,因此可以递归自身。 链长为c, 环长l, 则快慢指针第一次相遇时分别走了l',2l'步,l'为第一个大于c的l的倍数。
快慢指针相遇后,慢指针向前走c步,新指针从0同步c步,必将在环的入口处相遇。
未解决:使用位操作

300

O(n2):容易想到dp方法,dp[i]为结尾为nums[i]的最长递增串, dp[i] = max(dp[i],dp[j]+1) j O(nlogn): 借助lower_bound(v.begin(),v.end(),a) 简化程序。得到的数组不一定是LIS的数组。 构建数组v,遍历nums,若当前为v中最大,直接加入v;否则,替换v中第一个大于该数的数。
得到的数组只是满足最终数目条件的替代品,同时能满足算法的要求。

334

  • lower_bound(a, a+n, x):返回数组a[0]~a[n-1]中,【大于等于】x的数中,最小的数的指针
  • upper_bound(a, a+n, x):返回数组a[0]~a[n-1]中,【大于】x的数中,最小的数的指针

博客学习
O(nlogn):一开始想出的思路错误
O(n)时间,O(1)空间:因为大数要在后面,因此要在前面构造两个足够小的数m1, m2, 遍历,首先让m1足够小,否则让 m2足够小(m1 博客学习:构造forward[i]: 0---i-1最小的数;backward[i]: i+1---n最大的数,若 forward[i]

350

  • 容易想到:先分别排序,再遍历
  • 哈希表:nums1中出现的 哈希表中+1, nums2中也出现的,哈希表-1

待解决

  • What if the given array is already sorted? How would you optimize your algorithm?
  • What if nums1's size is small compared to nums2's size? Which algorithm is better?
  • What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once?

Week 4:

2020.3.29-4.5

hard:

10

讨论的情况比较多。

25

medium:

12

贪婪算法,对于1000,900,500,400,100,90,50,40,10,9,5,4,1分别对应。
待解决:时间空间待提高。使用map比使用两个vector慢一些。
map> map是可以排序的。

36

unordered_set
博客学习:比较巧妙,省内存,但时间不够好
使用set,行标注为 i(num),列标注为(num)j, 九宫格为 i/3(num)j/3
使用同样为m.count(num),m.insert()

48

较为经典的图像翻转
博客学习

  • 四个点依次换位
  • 首先以从对角线为轴翻转,然后再以x轴中线上下翻转
  • 先转置(swap(ij,ji)),后每行反转(用reverse(begin,end))

50

递归完成

89

递归的方法
如:00,01,11,10;
000,001,011,00,110,111,101,100
规律是在前面加0或1,加0可以不变照搬,加1要逆序

213

和之前的house robber的区别是第一个和最后一个不能同时偷,则使用max{rob(0,nums.size()-1),rob(0,nums.size()-1)}
博客学习:dp的空间优化版本
rob 为偷本次,notrob为本次不偷;
rob =prenotrob+cur;
notrob = max(prerob,prenotrob);

402

string resize(k) 截取string的前k个
string erase(iter)
很有启发的一道题目,能够想到移除的规律是移除第一个后一位开始下降的数字,即单调栈,仔细学习!
单调栈是抽象的数据结构,string实现即可。遍历一遍,维持结果为单调栈。
容易遗漏的点:

  • 遍历后要resize到指定尺寸,因为可能只是遍历完而非已经删了k位。
  • 要去除res开头的0, 如10200删1位结果0200
  • res为空时要返回“0”

477

统计出每位上1的个数即可,每位上的总汉明距离是1的个数*0的个数。
待优化:时间较为复杂
easy:

461

使用位操作,x xor y, num&=num-1可使最后一位1变为0

541

C++reverse: reverse(iterator1, iterator2)

你可能感兴趣的:(leetcode 刷题日记 week1-4)