about 2 pointers 3

Wed, Sep 1, 2021 9-minute read

Valid Palindrome 125

A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.

Given a string s, return true if it is a palindrome, or false otherwise.

 

Example 1:

Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
 public boolean isPalindrome(String s) {
        s = s.toLowerCase();
        if (s.length() == 0) {
            return true;
        }
        
        int i = 0, j = s.length() - 1;
        
        while (i < j) {
            while (i < j && !Character.isLetterOrDigit(s.charAt(i)) ) {
                i++;
            }
             while (i < j && !Character.isLetterOrDigit(s.charAt(j)) ) {
                j--;
            }
            if (s.charAt(i++) != s.charAt(j--)) {
                return false;
            }
          
        }
        return true;
    }

Assign Cookies 455

Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie.

Each child i has a greed factor g[i], which is the minimum size of a cookie that the child will be content with; and each cookie j has a size s[j]. If s[j] >= g[i], we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number.

 

Example 1:

Input: g = [1,2,3], s = [1,1]
Output: 1
Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3. 
And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content.
You need to output 1.
 public int findContentChildren(int[] g, int[] s) {
        int i = 0, j = 0;
        Arrays.sort(g);
        Arrays.sort(s);
        
        while (i < g.length && j < s.length) {
            if (s[j++] >= g[i]) {
                
                i++;
            }
            
        }
        return i;
    }

Reverse Only Letters 917

错误的

 char[] c = s.toCharArray();
        int i = 0, j = s.length() - 1;

        while (i <= j) {
            while(!Character.isLetter(c[i])) { 
                i++;
            } //这里i 到了3后,直接去了4
            while(!Character.isLetter(c[j])) {
                j--;
            } //这里j 到了3后,直接去了2

            // while(i < j && !Character.isLetter(c[i])) { 
            //     i++;
            // } // 正确的
            // while(i < j && !Character.isLetter(c[j])) {
            //     j--;
            // }  // 正确的
            char tmp = c[i]; 
            c[i++] = c[j]; // 导致 2, 4 又一次交换
            c[j--] = tmp;
        }
        return new String(c);

Long Pressed Name 925

Your friend is typing his name into a keyboard. Sometimes, when typing a character c, the key might get long pressed, and the character will be typed 1 or more times.

You examine the typed characters of the keyboard. Return True if it is possible that it was your friends name, with some characters (possibly none) being long pressed.

 

Example 1:

Input: name = "alex", typed = "aaleex"
Output: true
Explanation: 'a' and 'e' in 'alex' were long pressed.
 public boolean isLongPressedName(String name, String typed) {
      
        
        int i = 0;
        for(int j = 0; j <  typed.length(); ++j) {
            if (i < name.length() && name.charAt(i) == typed.charAt(j)) {
                i++;   
            } 
            else if (j == 0 || typed.charAt(j) != typed.charAt(j - 1)) {
                return false;
            } 
            
        }
         return i ==  name.length();      
    }

Interval List Intersections 986

You are given two lists of closed intervals, firstList and secondList, where firstList[i] = [starti, endi] and secondList[j] = [startj, endj]. Each list of intervals is pairwise disjoint and in sorted order.

Return the intersection of these two interval lists.

A closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b.

The intersection of two closed intervals is a set of real numbers that are either empty or represented as a closed interval. For example, the intersection of [1, 3] and [2, 4] is [2, 3].

Input: firstList = [[1,3],[5,9]], secondList = []
Output: []
      
        List<int[]> res = new ArrayList<>();
        int i = 0, j = 0;
        
        while (i < firstList.length && j < secondList.length) {
            int start = Math.max(firstList[i][0], secondList[j][0]);
            int end = Math.min(firstList[i][1], secondList[j][1]);
            
            if (start <= end) {
                res.add(new int[]{start, end});
            }
            if (firstList[i][1] < secondList[j][1]) {
                i++;
            } else {
                j++;
            }
        }
        // 一个二维 List<int[]> 转化成一个二维数组 int[][]
        return res.toArray(new int[0][] );
    }

Exam Room

There is an exam room with n seats in a single row labeled from 0 to n - 1.

When a student enters the room, they must sit in the seat that maximizes the distance to the closest person. If there are multiple such seats, they sit in the seat with the lowest number. If no one is in the room, then the student sits at seat number 0.

Design a class that simulates the mentioned exam room.

Implement the ExamRoom class:

ExamRoom(int n) Initializes the object of the exam room with the number of the seats n.
int seat() Returns the label of the seat at which the next student will set.
void leave(int p) Indicates that the student sitting at seat p will leave the room. It is guaranteed that there will be a student sitting at seat p.
 

Example 1:

Input
["ExamRoom", "seat", "seat", "seat", "seat", "leave", "seat"]
[[10], [], [], [], [], [4], []]
Output
[null, 0, 9, 4, 2, null, 5]

Explanation
ExamRoom examRoom = new ExamRoom(10);
examRoom.seat(); // return 0, no one is in the room, then the student sits at seat number 0.
examRoom.seat(); // return 9, the student sits at the last seat number 9.
examRoom.seat(); // return 4, the student sits at the last seat number 4.
examRoom.seat(); // return 2, the student sits at the last seat number 2.
examRoom.leave(4);
examRoom.seat(); // return 5, the student sits at the last seat number 5.

O(N) 时间复杂度

1 <= n <= 10^9 用数组会内存溢出

其实就是遍历,当有大量的空座位的时候,中间的 0 还得一个个遍历,不是很高效,那么比较直接的改进方法就是去掉那些 0,我们只保存有人坐的位置,即所有 1 的位置。这样省去了遍历 0 的时间,大大提高了效率,

class ExamRoom {
    List<Integer> list;
    int start = 0;
    int end;
    public ExamRoom(int n) {
        this.end = n - 1;
        list = new ArrayList<>();
    }
    
    public int seat() {
        if (list.size() == 0) {
            list.add(start);
            return start;
        }
        
        int max = Integer.MIN_VALUE;
        
        int pick = -1;
        int index = -1;
        
        if (list.get(0) != 0){
            pick = 0;
            max = list.get(0) - 0;
            index = 0;
        }
        
        int l = 0, r = 0;
        
        for (int i = 0; i < list.size(); i++) {
            if (i == 0) {
                l = list.get(0);
                continue;
            } else {
                l = r;
            }
                r = list.get(i);
                int mid = (l + r)/2;
                int dt = mid - l;
                if (dt > max) {
                    max = dt;
                    pick = mid;
                    index = i;
                }
            }
        
        
        if (list.get(list.size() - 1) < end) {
            l = list.get(list.size() - 1);
            r = end;
            int dt = r - l;
            if (dt > max) {
                max = dt;
                pick = r;
                index = list.size();
            }
        }
        
       
        list.add(index, pick);
        return pick;
    }
    
    public void leave(int p) {
      for (int i = 0; i < list.size() ; i++) {
          if (list.get(i) == p) {
              list.remove(i);
          }
      }
    }
}

TreeSet 有序集 OlogN

class ExamRoom {
    TreeSet<Integer> students;
    int N;
    

    public ExamRoom(int n) {
        this.N = n ;
        students = new TreeSet<>();
    }
    
    public int seat() {
       int student = 0;
       
        if (students.size() > 0) {
            int dist = students.first();
            Integer prev = null;
            for (Integer s : students) {
                if (prev != null) {
                    int d = (s - prev) / 2;
                    if (d > dist) {
                        dist = d;
                        student = prev + d;
                    }
                }
                prev = s;
            }
        }
// 边界。人离开后产生的情况
        if (N - 1 - students.last() > dist) {
            student = N - 1;
        }

        studnets.add(student);
        return student;
    }
    
    public void leave(int p) {
      students.remove(p);
    }
}


PriorityQueue 有序集 OlogN

class ExamRoom {
   class Interval {
        int start;
        int end;
        int length;
        public Interval(int start, int end) {
            this.start = start;
            this.end = end;
            if (start == 0 || end == N - 1) {
                this.length = end - start;
            } else {
                this.length = (end - start) / 2;
            }
        }
    }
    private PriorityQueue<Interval> pq;
    private int N;
    
    public ExamRoom(int N) {
        this.pq = new PriorityQueue<>((a, b) -> a.length != b.length ? b.length - a.length : a.start - b.start);
        this.N = N;
        pq.offer(new Interval(0, N - 1));
    }
    
    public int seat() {
        Interval in = pq.poll();
        int result;
        if (in.start == 0) {
            result = 0;
        } else if (in.end == N - 1) {
            result = N - 1;
        } else {
            result = in.start + in.length;
        }
        
        if (result > in.start) {
            pq.offer(new Interval(in.start, result - 1));   
        }
        if (in.end > result) {
            pq.offer(new Interval(result + 1, in.end));   
        }
        return result;
    }
    
    public void leave(int p) {
        List<Interval> list = new ArrayList(pq);
        Interval prev = null;
        Interval next = null;
        for (Interval in: list) {
            if (in.end + 1 == p) {
                prev = in;
            }
            if (in.start - 1 == p) {
                next = in;
            }
        }
        pq.remove(prev);
        pq.remove(next);
        pq.offer(new Interval(prev == null ? p : prev.start, next == null ? p : next.end));
        
    }

如果我们将考场中剩余的一段连续作为看作区间的话,那么每新来一个学生,当前能提供最大间隔的区间[l ,r]就将被划分为[l, p]以及[p, r]两段,其中 p 为新来的学生就座的位置;每离开一个学生,那么以离开的位置 p 为首尾的两端区间[l, p]以及[p, r]则会被重新合并为区间[l, r]。

于是接下来只需要解决两个问题:

1、如何选出当前能提供最大间隔的区间

2、如何通过离开的 p 定位到区间[l, p]以及[p, r]

对于问题一,使用堆来维护这些区间是很自然的想法。由于当前座位的编号为 0 到 n - 1,方便期间,我们假设初始区间为[-1, n]。那么对于一个区间[l, r]:

1-1)若 l = -1,那么学生必然坐在 0 这个位置上,因此该区间能提供的间隔就是 r

1-2)若 r = n,那么学生必然坐在 n - 1 这个位置上,因此该区间能提供的间隔就是 n - 1 - l

1-3)其他情况下,学生必然坐在区间的正中间,也就是 mid = (l + r) / 2,因此该区间能提供的间隔就是(r - l) / 2

有了上面这些比较准则,就可以根据区间能提供座位的间隔以及区间的左边界 l 的大小构造一个堆用来维护这些区间。

此时还需要解决问题 2。对于问题 2,一个自然的想法就是当一个学生就座之后,我们可以得到其座位 p,以及其坐在哪个[l, r]当中。此时则可以使用 head 和 tail 这两个 dict 保存以[p, r]这个区间在堆中编号以及[l, p]这个区间在堆中的编号。当座位 p 上的同学离开时,我们可以将 head[p]以及 tail[p]这两个区间从堆当中弹出,同时在弹出时获取到原始的 l 和 r 是多少,然后再将[l, r]加入到堆中。

使用 list 存所有座位的 index, 每次落座就 for loop 循环

26. Remove Duplicates from Sorted Array

Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same.

Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements.

Return k after placing the final result in the first k slots of nums.

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

Custom Judge:

The judge will test your solution with the following code:

int[] nums = [...]; // Input array
int[] expectedNums = [...]; // The expected answer with correct length
 public int removeDuplicates(int[] nums) {
       int j = 1;
        int i = 0;
        while (j < nums.length) {
            if (nums[j] != nums[j - 1]) {
                nums[++i] = nums[j];
            }
            j++;
        }
        return i + 1;
    }

😼😼😼😼


来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/MPnaiL

感谢:她们都有题库在 github 上直接有,都是大神, 都富有详细解法,对新人特别适合了解解题思路