给定一个整数数组 nums,处理以下类型的多个查询:
计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的 和 ,其中 left <= right
实现 NumArray 类:
NumArray(int[] nums) 使用数组 nums 初始化对象
int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + … + nums[right] )
class NumArray {
private int[] preNums;
public NumArray(int[] nums) {
preNums = new int[nums.length +1 ];
for(int i = 1 ; i < preNums.length;i++){
preNums[i] = preNums[i - 1] + nums[i-1];
}
}
public int sumRange(int left, int right) {
return preNums[right + 1] - preNums[left];
}
}
核⼼思路是我们 new ⼀个新的数组 preSum 出来,preSum[i] 记录 nums[0…i-1] 的累加和,(通俗的说就是先把每个前i项和求出来放在一个新的数组中,当在调用时不用每次都去用for循环遍历,让时间复杂度变为O(1)了)
看这个 preSum 数组,如果我想求索引区间 [1, 4] 内的所有元素之和,就可以通过 preSum[5] - preSum[1] 得出。
给定一个二维矩阵 matrix,以下类型的多个请求:
计算其子矩形范围内元素的总和,该子矩阵的 左上角 为 (row1, col1) ,右下角 为 (row2, col2) 。
实现 NumMatrix 类:
NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1) 、右下角 (row2, col2) 所描述的子矩阵的元素 总和 。
解题:
如果我想计算红⾊的这个⼦矩阵的元素之和,可以⽤绿⾊矩阵减去蓝⾊矩阵减去橙⾊矩阵最后加上粉⾊矩 阵,⽽绿蓝橙粉这四个矩阵有⼀个共同的特点,就是左上⻆就是 (0, 0) 原点。 那么我们可以维护⼀个⼆维 preSum 数组,专⻔记录以原点为顶点的矩阵的元素之和,就可以⽤⼏次加减运 算算出任何⼀个⼦矩阵的元素和:
private int[][] preSum;
public void NumMatrix(int[][] matrix) {
int m = matrix.length , n = matrix[0].length;
if(m == 0 || n == 0){
return;
}
//构造数组
preSum = new int[m + 1][n + 1];
for(int i = 1 ; i <= m; i++ ){
for(int j = 1;j <= n; j++){
// 计算每个矩阵[0,0,i,j]的元素和
preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] -preSum[i - 1][j - 1];
}
}
}
/**
* 计算子矩阵[row1,col1,row2,col2] 的元素和
*/
public int sumRegion(int row1,int col1,introw2,int col2){
// 目标矩阵之和有四个相邻矩阵运算获得
return preSum[row2 + 1,col2 + 1] - preSum[row2+1][col1] - preSum[row1][col2 + 1] + preSum[row1][col1];
}
给你一个整数数组 nums 和一个整数 k ,请你统计并返回该数组中和为 k 的连续子数组的个数。
示例 1:
输入:nums = [1,1,1], k = 2
输出:2
示例 2:
输入:nums = [1,2,3], k = 3
输出:2
public int subarraySum(int[] nums,int k){
int n = nums.length;
// 构造前缀和
int[] preSum = new int[n+1];
for(int i = 1; i < n + 1 ; i++){
preSum[i] = perSum[i-1] + nums[i-1];
}
// 记录满足条件子数组数
int res = 0;
// 穷举出所有子数组
for(int i = 1 ; i <= n ;i++){
for(int j = 0 ; j < i;j++){
// 子数组 nums[j...i-1] 的元素和
if(preSum[i] - preSum[j] == k){
res++;
}
}
}
return res;
}
官方答案:
java:
public class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
for (int start = 0; start < nums.length; ++start) {
int sum = 0;
for (int end = start; end >= 0; --end) {
sum += nums[end];
if (sum == k) {
count++;
}
}
}
return count;
}
}
go:
func subarraySum(nums []int, k int) int {
n := len(nums)
res := 0
for i := 1; i <= n; i++ {
sum := 0
for j := i -1; j >= 0; j-- {
sum += nums[j]
if sum == k {
res++
}
}
}
return res
}
class Difference {
// 差分数组
private int[] diff;
public Difference(int[] nums) {
// 初始化差分数组
diff = new int[nums.length];
// 根据初始数组给差分数组赋值
diff[0] = nums[0];
for(int i = 0; i < nums.length ; i++){
diff[i] = nums[i] - nums[i-1];
}
}
/**
* 给闭区间[i,j] 增加val
*/
public void increment(int i,int j,int val){
diff[i] += val;
if(j+1 < diff.lenth){
diff[j + 1] -= val;
}
}
public int[] result(){
int[] result = new int[diff.length]
// 根据差分数组构造结果集
result[0] = diff[0];
for(int i = 1; i < diff.length;i++){
result[i] = diff[i] + result[i-1];
}
return result;
}
}
public int[] getModifiedArray(int length ,int[][] updates){
// 初始化数组
int[] nums = new int[lenrth];
// 构造差分解法
Difference diff = new Difference(nums);
for(int[] update : updates){
int i = update[0];
int j = update[1];
int val = update[2]
diff.increment(i,j,val);
}
return diff.result();
}
class Solution {
// 定义差分数组
private int[] diff;
public int[] corpFlightBookings(int[][] bookings, int n) {
diff = new int[n];
diff[0] = 0;
for(int[] booking:bookings){
int i = booking[0] - 1;
int j = booking[1] - 1;
int val = booking[2];
increment(i,j,val);
}
// 根据差分数组构造结果集
int[] res = new int[n];
res[0] = diff[0];
for(int i=1;i < n ;i++){
res[i] = res[i-1] + diff[i];
}
return res;
}
/**
* 给闭区间[i,j] 增加val
*/
public void increment(int i,int j,int val){
diff[i] += val;
if(j+1 < diff.length){
diff[j+1] -= val;
}
}
}
GO:
// 定义差分数组
var diff []int
func corpFlightBookings(bookings [][]int, n int) []int {
diff = make([]int, n)
for _, booking := range bookings {
i := booking[0] - 1
j := booking[1] - 1
val := booking[2]
increment(i, j, val)
}
// 根据差分数组构造结果集
res := make([]int, n)
res[0] = diff[0]
for i := 1; i < n; i++ {
res[i] = res[i-1] + diff[i]
}
return res
}
/**
* 给闭区间[i,j] 增加val
*/
func increment(i, j, val int) {
diff[i] += val
if (j + 1) < len(diff) {
diff[j+1] -= val
}
}
解题思路:
把所有站看做一个数组,每位乘客所在的乘车区间为 [i,j] ,那么第 i 站到 j 站乘客就增加相应数量。记录每站车上的乘客数量,当某站的乘客超过 车的位置数量时就不能,反之则能。
class Solution {
int[] diff;
public boolean carPooling(int[][] trips, int capacity) {
// 因为题目中有 trips.length <= 1000 ,所以...
diff = new int[1001];
diff[0] = 0;
// 利用分差数组记录每站的乘客数量
for(int[] trip: trips){
int val = trip[0];
int i = trip[1];
int j = trip[2] -1;
increment(i,j,val);
}
// 根据差分数组返回结果集,返回每站乘客的数量
int[] res = new int[diff.length];
res[0] = diff[0];
for(int i = 1;i< diff.length;i++){
res[i] = res[i-1] + diff[i];
}
for(int i =0 ; i <res.length;i++){
// 如果某站乘客数量 超过 车的位置数 则不能
if(capacity < res[i]){
return false;
}
}
return true;
}
// 增加 i 到 j 站的乘客数量
public void increment(int i,int j,int val){
diff[i] += val;
if(j+1 < diff.length){
diff[j+1] -= val;
}
}
}
GO:
var diff []int
func carPooling(trips [][]int, capacity int) bool {
diff = make([]int, 1001)
for _, trip := range trips {
val := trip[0]
i := trip[1]
j := trip[2] - 1
increment(i, j, val)
}
res := make([]int, 1001)
res[0] = diff[0]
for i := 1; i < len(diff); i++ {
res[i] = res[i-1] + diff[i]
}
for i := 0; i < len(res); i++ {
if capacity < res[i] {
return false
}
}
return true
}
func increment(i, j, val int) {
diff[i] += val
if (j + 1) < len(diff) {
diff[j+1] -= val
}
}
class Solution {
Map<Character, Integer> ori = new HashMap<Character, Integer>();
Map<Character, Integer> cnt = new HashMap<Character, Integer>();
public String minWindow(String s, String t) {
int tLen = t.length();
for (int i = 0; i < tLen; i++) {
char c = t.charAt(i);
ori.put(c, ori.getOrDefault(c, 0) + 1);
}
int l = 0, r = -1;
int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
int sLen = s.length();
while (r < sLen) {
++r;
if (r < sLen && ori.containsKey(s.charAt(r))) {
cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
}
while (check() && l <= r) {
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
ansR = l + len;
}
if (ori.containsKey(s.charAt(l))) {
cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
}
++l;
}
}
return ansL == -1 ? "" : s.substring(ansL, ansR);
}
public boolean check() {
Iterator iter = ori.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Character key = (Character) entry.getKey();
Integer val = (Integer) entry.getValue();
if (cnt.getOrDefault(key, 0) < val) {
return false;
}
}
return true;
}
}
判定链表中是否含有环
如果不含有环,跑得快的那个指针最终会遇到 null
,说明链表不含环;如果含有环,快指针最终会超慢指针一圈,和慢指针相遇,说明链表含有环。
Java:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode fast,slow;
fast = slow = head;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
return true;
}
}
return false;
}
}
Go:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func hasCycle(head *ListNode) bool {
fast := head
slow := head
for fast != nil && fast.Next != nil {
fast = fast.Next.Next
slow = slow.Next
if fast == slow {
return true
}
}
return false
}
已知链表中含有环,返回这个环的起始位置
第一次相遇时,假设慢指针 slow
走了 k
步,那么快指针 fast
一定走了 2k
步:
fast
一定比 slow
多走了 k
步,这多走的 k
步其实就是 fast
指针在环里转圈圈,所以 k
的值就是环长度的「整数倍」。
设相遇点距环的起点的距离为 m
,那么环的起点距头结点 head
的距离为 k - m
,也就是说如果从 head
前进 k - m
步就能到达环起点。
巧的是,如果从相遇点继续前进 k - m
步,也恰好到达环起点。你甭管 fast
在环里到底转了几圈,反正走 k
步可以到相遇点,那走 k - m
步一定就是走到环起点了:
所以,只要我们把快慢指针中的任一个重新指向 head
,然后两个指针同速前进,k - m
步后就会相遇,相遇之处就是环的起点了。
Java:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast,slow;
fast = slow = head;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow ){
break;
}
}
if (fast == null || fast.next == null){
return null;
}
slow = head;
while (fast != slow){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
Go:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func detectCycle(head *ListNode) *ListNode {
fast := head
slow := head
for fast != nil && fast.Next != nil{
fast = fast.Next.Next
slow = slow.Next
if fast == slow {
break
}
}
if fast == nil || fast.Next == nil {
return nil
}
slow = head
for slow != fast{
fast = fast.Next
slow = slow.Next
}
return slow
}
Java:
class Solution {
public int[] twoSum(int[] numbers, int target) {
int left = 0, right = numbers.length - 1;
int sum = 0;
while (left < right) {
sum = numbers[right] + numbers[left];
if (sum == target) {
return new int[]{left + 1, right + 1};
} else if (sum < target) {
left++;
} else if (sum > target) {
right--;
}
}
return new int[]{-1, -1};
}
}
Go:
func twoSum(numbers []int, target int) []int {
left := 0
right := len(numbers) - 1
sum := 0
for left < right {
sum = numbers[left] + numbers[right]
if sum == target {
// 题目要求的索引是从 1 开始的
res := []int{left + 1, right + 1}
return res
} else if sum < target { // 让 sum 大一点
left++
} else if sum > target { // 让 sum 小一点
right--
}
}
return []int{-1, - 1}
}
Java:
class Solution {
public void reverseString(char[] s) {
int left = 0;
int right = s.length -1;
while(left < right){
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
System.out.println(s);
}
}
Go:
func reverseString(s []byte) {
left:= 0
right := len(s) - 1
for left < right {
temp := s[left]
s[left] = s[right]
s[right] = temp
left++
right--
}
fmt.Println(s)
}
class Solution {
/**
* 记录t中的所有字符,以及在s中出现的次数
*/
Map<Character, Integer> needs = new HashMap<Character, Integer>();
/**
* 滑动窗口
*/
Map<Character, Integer> window = new HashMap<Character, Integer>();
public String minWindow(String s, String t) {
int tLength = t.length();
// 把t中的所有字符加入 needs中
for (int i = 0; i < tLength; i++) {
char c = t.charAt(i);
needs.put(c, needs.getOrDefault(c, 0) + 1);
}
int left = 0, right = 0;
// 窗⼝中满⾜ needs 条件的字符个数
int valid = 0;
// 记录最⼩覆盖⼦串的起始索引及⻓度
int start = 0, len = Integer.MAX_VALUE;
int sLength = s.length();
while (right < sLength) {
// c 是将移⼊窗⼝的字符
char c = s.charAt(right);
// 右移窗⼝
right++;
// 进⾏窗⼝内数据的⼀系列更新
if (needs.containsKey(c)) {
window.put(c, window.getOrDefault(c, 0) + 1);
if (window.get(c).equals(needs.get(c))) {
valid++;
}
}
// 判断左侧窗⼝是否要收缩
while (valid == needs.size()) {
// 在这⾥更新最⼩覆盖⼦串
if (right - left < len) {
start = left;
len = right - left;
}
// d 是将移出窗⼝的字符
char d = s.charAt(left);
// 左移窗⼝
left++;
// 进⾏窗⼝内数据的⼀系列更新
if (needs.containsKey(d)) {
if (window.get(d).equals(needs.get(d))) {
valid--;
}
window.put(d, window.getOrDefault(d, 0) - 1);
}
}
}
// 返回最⼩覆盖⼦串
return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
}
}
func minWindow(s string, t string) string {
need := make(map[string]int)
windows := make(map[string]int)
for i := 0; i < len(t); i++ {
need[t[i:i+1]]++
}
left := 0
right := 0
valid := 0
start := 0
le := math.MaxInt32
for right < len(s) {
c := s[right : right+1]
right++
_, ok := need[c]
if ok {
windows[c]++
if windows[c] == need[c] {
valid++
}
}
for valid == len(need) {
if right-left < le {
start = left
le = right - left
}
d := s[left : left+1]
left++
_, ok := need[d]
if ok {
if windows[d] == need[d] {
valid--
}
windows[d]--
}
}
}
if le == math.MaxInt32 {
return ""
}
return s[start : start+le]
}
Java:
class Solution {
/**
* 记录t中的所有字符,以及在s中出现的次数
*/
Map<Character, Integer> needs = new HashMap<Character, Integer>();
/**
* 滑动窗口
*/
Map<Character, Integer> window = new HashMap<Character, Integer>();
public boolean checkInclusion(String s1, String s2) {
for (int i = 0; i < s1.length(); i++) {
needs.put(s1.charAt(i), needs.getOrDefault(s1.charAt(i), 0) + 1);
}
int left = 0, right = 0;
int valid = 0;
while (right < s2.length()) {
char c = s2.charAt(right);
right++;
if (needs.containsKey(c)) {
window.put(c, window.getOrDefault(c, 0) + 1);
if (needs.get(c).equals(window.get(c))) {
valid++;
}
}
while (right - left >= s1.length()) {
if (valid == needs.size()) {
return true;
}
char d = s2.charAt(left);
left++;
if (needs.containsKey(d)) {
if (needs.get(d).equals(window.get(d))) {
valid--;
}
window.put(d, window.getOrDefault(d, 0) - 1);
}
}
}
return false;
}
}
Go:
func checkInclusion(s1 string, s2 string) bool {
need := make(map[string]int)
windows := make(map[string]int)
// 把s1中的字符 放入need中
for i:= 0 ; i < len(s1) ; i++ {
need[s1[i:i+1]]++
}
left := 0
right := 0
valid := 0
for right < len(s2) {
c := s2[right:right+1]
right++
// 进行窗口内一系列更新
_ ,ok := need[c]
if ok {
windows[c]++
if need[c] == windows[c] {
valid++
}
}
// 判断左窗口是否要收缩
for right - left >= len(s1) {
// 这里判断找到合法的字符串
if valid == len(need) {
return true
}
d :=s2[left:left+1]
left++
// 进行窗口内一些列数据更新
_ ,ok:=need[d]
if ok {
if windows[d] == need[d]{
valid--
}
windows[d]--
}
}
}
// 没有找到合法字符串
return false
}
Java:
class Solution {
/**
* 记录t中的所有字符,以及在s中出现的次数
*/
Map<Character, Integer> needs = new HashMap<Character, Integer>();
/**
* 滑动窗口
*/
Map<Character, Integer> window = new HashMap<Character, Integer>();
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new ArrayList<Integer>();
for (int i = 0; i < p.length(); i++) {
needs.put(p.charAt(i), needs.getOrDefault(p.charAt(i), 0) + 1);
}
int left = 0, right = 0;
int valid = 0;
while (right < s.length()) {
char c = s.charAt(right);
right++;
if (needs.containsKey(c)) {
window.put(c, window.getOrDefault(c, 0) + 1);
if (needs.get(c).equals(window.get(c))) {
valid++;
}
}
while (right - left >= p.length()) {
if (valid == needs.size()) {
res.add(left);
}
char d = s.charAt(left);
left++;
if (needs.containsKey(d)) {
if (needs.get(d).equals(window.get(d))) {
valid--;
}
window.put(d, window.getOrDefault(d, 0) - 1);
}
}
}
return res;
}
}
Go:
func findAnagrams(s string, p string) []int {
need := make(map[string]int)
window := make(map[string]int)
var res []int
for i := 0; i < len(p); i++ {
need[p[i:i+1]]++
}
left := 0
right := 0
valid := 0
for right < len(s) {
c := s[right : right+1]
right++
_, ok := need[c]
if ok {
window[c]++
if need[c] == window[c] {
valid++
}
}
for right - left >= len(p) {
if valid == len(need) {
res = append(res,left)
}
d := s[left : left+1]
left++
_, ok := need[d]
if ok {
if need[d] == window[d] {
valid--
}
window[d]--
}
}
}
return res
}
Java:
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> window = new HashMap<Character, Integer>();
int left = 0, right = 0;
int res = 0;
while (right < s.length()) {
char c = s.charAt(right);
right++;
window.put(c, window.getOrDefault(c, 0) + 1);
// 如果新加入的字符使windon中的字符数量大于1了,就该收缩窗口了
while (window.get(c) > 1) {
char d = s.charAt(left);
left++;
window.put(d, window.getOrDefault(d, 0) - 1);
}
res = Math.max(res, right - left);
}
return res;
}
}
Go:
func lengthOfLongestSubstring(s string) int {
window := make(map[string]int)
left := 0
right := 0
res := 0
for right < len(s) {
c := s[right : right+1]
right++
window[c]++
for window[c] > 1 {
d := s[left : left+1]
left++
window[d]--
}
res = int(math.Max(float64(res), float64(right-left)))
}
return res
}
寻找⼀个数(基本的⼆分搜索)
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // 注意
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意
else if (nums[mid] > target)
right = mid - 1; // 注意
}
return -1;
}
初始化right == nums.length - 1
, 相当于两端都闭区间 [left, right]
while (left <= right)
,终⽌的条件是left == right + 1
因为我们初始化 right = nums.length - 1
所以决定了我们的「搜索区间」是 [left, right]
所以决定了 while (left <= right)
同时也决定了 left = mid+1 和 right = mid-1
因为我们只需找到⼀个 target 的索引即可
所以当 nums[mid] == target 时可以⽴即返回
寻找左侧边界的⼆分搜索
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length; // 注意
while (left < right) { // 注意
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // 注意
}
}
return left;
}
right = nums.length
每次循环的「搜 索区间」是 [left, right) 左闭右开。
while(left < right)
终⽌的条件是left == right
,此时搜索区间 [left, left) 为空,所以可以 正确终⽌。
因为我们初始化 right = nums.length
所以决定了我们的「搜索区间」是 [left, right)
所以决定了 while (left < right)
同时也决定了 left = mid + 1 和 right = mid
因为我们需找到 target 的最左侧索引
所以当 nums[mid] == target 时不要⽴即返回
⽽要收紧右侧边界以锁定左侧边界
寻找右侧边界的⼆分查找
int right_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0, right = nums.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
left = mid + 1; // 注意
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
return left - 1; // 注意
}
因为我们初始化 right = nums.length
所以决定了我们的「搜索区间」是 [left, right)
所以决定了 while (left < right)
同时也决定了 left = mid + 1 和 right = mid
因为我们需找到 target 的最右侧索引
所以当 nums[mid] == target 时不要⽴即返回
⽽要收紧左侧边界以锁定右侧边界
⼜因为收紧左侧边界时必须 left = mid + 1
所以最后⽆论返回 left 还是 right,必须减⼀
总结:
// 基本二分搜索
int binary_search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}
// 寻找左侧的二分搜索
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定左侧边界
right = mid - 1;
}
}
// 最后要检查 left 越界的情况
if (left >= nums.length || nums[left] != target) {
return -1;
}
return left;
}
// 寻找右侧的二分搜索
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定右侧边界
left = mid + 1;
}
}
// 最后要检查 right 越界的情况
if (right < 0 || nums[right] != target) {
return -1;
}
return right;
}
Java:
class Solution {
public int search(int[] nums, int target) {
int left = 0,right = nums.length - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if (nums[mid] == target){
return mid;
}else if (nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}
}
return -1;
}
}
Go:
func search(nums []int, target int) int {
left := 0
right := len(nums) - 1
for left <= right {
mid:= left + (right - left) / 2
if nums[mid] == target {
return mid
} else if target > nums[mid] {
left = mid + 1
}else if target < nums[mid] {
right = mid - 1
}
}
return -1
}
Java:
class Solution {
public int[] searchRange(int[] nums, int target) {
int indexLeft = binarySearch(nums, target, true);
int indexRight = binarySearch(nums, target, false);
if (indexLeft >= nums.length || nums[indexLeft] != target || indexRight < 0 || nums[indexRight] != target) {
return new int[]{-1, -1};
}
return new int[]{indexLeft, indexRight};
}
public int binarySearch(int[] nums, int target, boolean lower) {
// lower true 左 false右
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (target > nums[mid]) {
left = mid + 1;
} else if (target < nums[mid]) {
right = mid - 1;
} else if (target == nums[mid]) {
if (lower) {
// 左
right = mid - 1;
} else {
left = mid + 1;
}
}
}
if (lower){
return left;
}
return right;
}
}
Go:
func searchRange(nums []int, target int) []int {
leftIndex := binarySearch(nums,target,true)
rightIndex := binarySearch(nums,target,false)
if (leftIndex >= len(nums) || nums[leftIndex] != target || rightIndex < 0 || nums[rightIndex] != target){
return []int{-1,-1}
}
return []int{leftIndex,rightIndex}
}
func binarySearch(nums []int, target int,flag bool) int {
left := 0
right := len(nums) - 1
for left <= right {
mid := left + (right - left)
if target > nums[mid] {
left = mid + 1
}else if target < nums[mid]{
right = mid - 1
}else if target == nums[mid]{
if flag {
right = mid -1
}else{
left = mid + 1
}
}
}
if flag{
return left
}
return right
}
Java:
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int left = 1;
int right = 1000000000 - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
// time 递减 当 time <= H 时应该左移 ,反之右移
if (!possible(piles, h, mid)) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
public boolean possible(int[] piles, int H, int K) {
int time = 0;
for (int pile : piles) {
time += (pile - 1) / K + 1;
}
return time <= H;
}
}
Go:
func minEatingSpeed(piles []int, h int) int {
left := 1
right := 1000000000 -1
for left <= right {
mid := left + (right - left) / 2
if !possible(piles,h,mid) {
left = mid + 1
}else {
right = mid -1
}
}
return left
}
func possible(piles []int,h int,k int) bool {
time:= 0
for _,pile := range piles{
time += (pile - 1) / k + 1
}
return time <= h
}
因为船至少运走一件包裹,所以,left = weights中的最大值 ,最快一次运走,所以 right = weights中所有元素的总会。
Java:
class Solution {
public int shipWithinDays(int[] weights, int days) {
int left = Arrays.stream(weights).max().getAsInt(), right = Arrays.stream(weights).sum();
while (left < right){
int mid = left + (right - left ) / 2;
// need 为需要运送的天数
// sum 为当前这一天已经运送的包裹重量之和
int need = 1,sum = 0;
for (int weight : weights){
if (sum + weight > mid){
need++;
sum = 0;
}
sum += weight;
}
if (need <= days){
right = mid;
}else{
left = mid + 1;
}
}
return left;
}
}
Go:
func shipWithinDays(weights []int, days int) int {
left := 0
right := 0
for _,w := range weights {
if w > left {
left = w
}
right += w
}
right--
for left <= right {
mid := left + (right - left ) / 2
sum:= 0
need := 1
for _, weight :=range weights {
if sum+weight > mid {
need++
sum = 0
}
sum += weight
}
if need <= days {
right = mid - 1
}else {
left = mid + 1
}
}
return left
}
Java:
class Solution {
int[] advantageCount(int[] nums1, int[] nums2) {
int n = nums1.length;
// 给 nums2 降序排序
PriorityQueue<int[]> maxpq = new PriorityQueue<>(
(int[] pair1, int[] pair2) -> {
return pair2[1] - pair1[1];
}
);
for (int i = 0; i < n; i++) {
maxpq.offer(new int[]{i, nums2[i]});
}
// 给 nums1 升序排序
Arrays.sort(nums1);
// nums1[left] 是最小值,nums1[right] 是最大值
int left = 0, right = n - 1;
int[] res = new int[n];
while (!maxpq.isEmpty()) {
int[] pair = maxpq.poll();
// maxval 是 nums2 中的最大值,i 是对应索引
int i = pair[0], maxval = pair[1];
if (maxval < nums1[right]) {
// 如果 nums1[right] 能胜过 maxval,那就自己上
res[i] = nums1[right];
right--;
} else {
// 否则用最小值混一下,养精蓄锐
res[i] = nums1[left];
left++;
}
}
return res;
}
}
让慢指针 slow ⾛在后⾯,快指针 fast ⾛在前⾯探路,找到⼀个不重复的元素就告诉 slow 并让 slow 前进⼀步。这样当 fast 指针遍历完整个数组 nums 后,nums[0…slow] 就是不重复元素。
class Solution {
public int removeDuplicates(int[] nums) {
if (nums.length == 0){
return 0;
}
int slow = 0,fast = 0;
while(fast < nums.length){
if(nums[slow] != nums[fast]){
slow++;
nums[slow] = nums[fast];
}
fast++;
}
return slow + 1;
}
}
Go:
func removeDuplicates(nums []int) int {
if len(nums) == 0 {
return 0
}
slow:= 0
fast := 0
for fast < len(nums) {
if nums[slow] != nums[fast] {
slow++
nums[slow] = nums[fast]
}
fast++
}
return slow + 1
}
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null){
return null;
}
ListNode slow ,fast;
slow = fast = head;
while(fast != null){
if(slow.val != fast.val){
slow.next = fast;
slow = slow.next;
}
fast = fast.next;
}
slow.next = null;
return head;
}
}
Go:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func deleteDuplicates(head *ListNode) *ListNode {
if head == nil {
return nil;
}
slow := head
fast := head
for fast != nil {
if slow.Val != fast.Val {
slow.Next = fast
slow = slow.Next
}
fast = fast.Next
}
slow.Next = nil
return head
}
Java:
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0,fast = 0;
while(fast < nums.length){
if (val != nums[fast]){
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}
}
Go:
func removeElement(nums []int, val int) int {
slow := 0
fast := 0
for fast < len(nums) {
if val != nums[fast] {
nums[slow] = nums[fast]
slow++
}
fast++
}
return slow
}
Java:
class Solution {
public void moveZeroes(int[] nums) {
if(nums==null) {
return;
}
//第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
int j = 0;
for(int i=0;i<nums.length;++i) {
if(nums[i]!=0) {
nums[j++] = nums[i];
}
}
//非0元素统计完了,剩下的都是0了
//所以第二次遍历把末尾的元素都赋为0即可
for(int i=j;i<nums.length;++i) {
nums[i] = 0;
}
}
}
class Solution {
public void moveZeroes(int[] nums) {
//两个指针i和j
int j = 0;
for (int i = 0; i < nums.length ; i++){
//当前元素!=0,就把其交换到左边,等于0的交换到右边
if (nums[i] != 0){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
j++;
}
}
}
}
class Solution {
void moveZeroes(int[] nums) {
// 去除 nums 中的所有 0
// 返回去除 0 之后的数组⻓度
int p = removeElement(nums, 0);
// 将 p 之后的所有元素赋值为 0
for (; p < nums.length; p++) {
nums[p] = 0;
}
}
// 移除 nums 中值为 val 的所有值 返回nums移除目标值后的长度
public int removeElement(int[] nums, int val) {
int slow = 0, fast = 0;
while (fast < nums.length) {
if (val != nums[fast]) {
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}
}
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode temp = new ListNode(-1);
ListNode p1 = list1,p2 = list2,p = temp;
while(p1 != null && p2 != null){
if (p1.val < p2.val){
p.next = p1;
p1 =p1.next;
}else {
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if (p1 != null){
p.next = p1;
}
if (p2 != null){
p.next =p2;
}
return temp.next;
}
}
Go:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeTwoLists(p1 *ListNode, p2 *ListNode) *ListNode {
var preHead = new(ListNode)
var prev *ListNode
prev = preHead
for p1 !=nil && p2 !=nil{
if p1.Val < p2.Val {
prev.Next = p1
p1 = p1.Next
}else {
prev.Next = p2
p2 = p2.Next
}
prev = prev.Next
}
if p1 !=nil{
prev.Next = p1
}
if p2 != nil {
prev.Next = p2
}
return preHead.Next
}
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
// 虚拟头结点
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
// 优先队列 最小堆
PriorityQueue<ListNode> priorityQueue = new PriorityQueue<>(
lists.length, (a, b) -> (b.val - a.val));
// 将k个链表的头结点加入最小堆
for (ListNode head : lists) {
if (head != null) {
priorityQueue.add(head);
}
}
while (!priorityQueue.isEmpty()) {
ListNode node = priorityQueue.poll();
p.next = node;
if (node.next != null) {
priorityQueue.add(node.next);
}
p = p.next;
}
return dummy.next;
}
}
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast,slow,temp;
fast = slow = head;
temp = head;
// 快指针先前进 n 步
for (int i = 0 ; i < n ;i++){
fast = fast.next;
}
if (fast == null){
// 如果此时快指针走到头了,
// 说明倒数第 n 个节点就是第一个节点
return head.next;
}
// 让慢指针和快指针同步向前
while (fast != null && fast.next != null){
fast = fast.next;
slow = slow.next;
}
// slow.next 就是倒数第 n 个节点,删除它
slow.next = slow.next.next;
return head;
}
}
Go:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeNthFromEnd(head *ListNode, n int) *ListNode {
fast := head
slow := head
for i:= 0;i<n;i++ {
fast = fast.Next
}
if fast == nil {
return head.Next
}
for fast != nil && fast.Next != nil {
fast = fast.Next
slow = slow.Next
}
slow.Next = slow.Next.Next
return head
}
Java:
快慢指针
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast,slow;
fast = slow = head;
while (fast != null && fast.next !=null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
Go:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func middleNode(head *ListNode) *ListNode {
fast := head
slow := head
for fast != nil && fast.Next != nil{
fast = fast.Next.Next
slow = slow.Next
}
return slow
}
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode pa = headA,pb = headB;
while (pa != pb){
if (pa == null){
pa = headB;
}else {
pa = pa.next;
}
if (pb == null){
pb = headA;
}else {
pb = pb.next;
}
}
return pa;
}
}
Go:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
pa := headA
pb := headB
for pa != pb {
if pa == nil {
pa = headB
}else {
pa = pa.Next
}
if pb == nil {
pb = headA
}else {
pb = pb.Next
}
}
return pb
}
方法一:重新创造个链表,把目标链表一个一个的插入新的链表头结点后面
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode n = new ListNode(-1);
ListNode p,temp;
p = head;
while (p != null){
temp = p;
p = p.next;
temp.next = n.next;
n.next = temp;
}
return n.next;
}
}
方法二:递归
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null){
return head;
}
ListNode last = reverseList(head.next);
head.next.next = head;
head.next = null;
return last;
}
}
方法一:递归
Java:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
ListNode successor = null; // 后驱节点
public ListNode reverseN(ListNode head, int n) {
if (n == 1) {
// 记录第 n + 1 个结点
successor = head.next;
return head;
}
// 以head.next 为起点,需要反转前 n - 1 个结点
ListNode last = reverseN(head.next, n - 1);
head.next.next = head;
// 让反转之后的 head 节点和后面的节点连起来
head.next = successor;
return last;
}
public ListNode reverseBetween(ListNode head, int left, int right) {
if (left == 1) {
return reverseN(head, right);
}
head.next = reverseBetween(head.next, left - 1, right - 1);
return head;
}
}
方法二:
public ListNode reverseBetween(ListNode head, int left, int right) {
// 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode pre = dummyNode;
// 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点
// 建议写在 for 循环里,语义清晰
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
// 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
ListNode rightNode = pre;
for (int i = 0; i < right - left + 1; i++) {
rightNode = rightNode.next;
}
// 第 3 步:切断出一个子链表(截取链表)
ListNode leftNode = pre.next;
ListNode curr = rightNode.next;
// 注意:切断链接
pre.next = null;
rightNode.next = null;
// 第 4 步:同第 206 题,反转链表的子区间
reverseList(leftNode);
// 第 5 步:接回到原来的链表中
pre.next = rightNode;
leftNode.next = curr;
return dummyNode.next;
}
Java:
class MyQueue {
Stack<Integer> s1, s2;
public MyQueue() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public void push(int x) {
s1.push(x);
}
/**
* 出队:
* 删除队头元素并返回
*/
public int pop() {
peek();
return s2.pop();
}
/**
* 返回队头元素
*/
public int peek() {
// 把s1 元素 压入 s2
if (s2.isEmpty()){
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
}
return s2.peek();
}
public boolean empty() {
return s1.isEmpty() && s2.isEmpty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
Java:
class MyStack {
Queue<Integer> q = new LinkedList<>();
int top_elem = 0;
public MyStack() {
}
/**
* 添加元素到栈顶
*/
public void push(int x) {
// x是队尾 ,同时也是栈顶
q.offer(x);
top_elem = x;
}
/**
* 删除栈顶的元素并返回
*/
public int pop() {
int size = q.size();
while (size > 2) {
q.offer(q.poll());
size--;
}
// 记录新的队尾元素
top_elem = q.peek();
q.offer(q.poll());
return q.poll();
}
/**
* 返回栈顶元素
*/
public int top() {
return top_elem;
}
/**
* 判断栈是否为空
*/
public boolean empty() {
return q.isEmpty();
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/
20. 有效的括号(简单)
Java:
class Solution {
public boolean isValid(String s) {
char[] chars = s.toCharArray();
Stack<Character> left = new Stack<>();
for (char c : chars) {
if (c == '(' || c == '[' || c == '{') {
left.push(c);
} else {
// 字符 c 是右括号
if (!left.empty() && leftOf(c) == left.peek()) {
left.pop();
} else {
// 和最近的左括号不匹配
return false;
}
}
}
return left.empty();
}
char leftOf(char c) {
if (c == ')') {
return '(';
}
if (c == ']') {
return '[';
}
return '{';
}
}
Java:
class Solution {
public int minAddToMakeValid(String s) {
char[] chars = s.toCharArray();
// res 记录插入次数
int res = 0;
// need 记录右括号的需求量
int need = 0;
for (int i = 0; i < s.length(); i++) {
if (chars[i] == '(') {
need++;
}
if (chars[i] == ')') {
need--;
}
if (need == -1) {
need = 0;
res++;
}
}
return res + need;
}
}
Java:
class Solution {
public int minInsertions(String s) {
char[] chars = s.toCharArray();
int res = 0, need = 0;
for (int i = 0; i < s.length(); i++) {
if (chars[i] == '(') {
need += 2;
if (need % 2 == 1) {
// 插入一个右括号
res++;
// 对右括号的需求减一
need--;
}
}
if (chars[i] == ')') {
need--;
// 说明右括号太多了
if (need == -1) {
// 需要插入一个左括号
res++;
// 同时,对右括号的需求变为 1
need = 1;
}
}
}
return res + need;
}
}
解题思想
Java:
迭代法
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
// 结果数组
int[] result = new int[nums1.length];
// 标记num2 中 对应的位置
boolean flag = false;
for (int i = 0; i < nums1.length; i++) {
// 先设置为-1 没找到
result[i] = -1;
for (int j = 0; j < nums2.length; j++) {
if (nums2[j] == nums1[i]) {
// 找到对应位置
flag = true;
continue;
}
if (flag && nums2[j] > nums1[i]) {
// 找到赋值
result[i] = nums2[j];
break;
}
}
// 找一个元素前标记重置
flag = false;
}
return result;
}
}
Java:
解题
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] result = new int[temperatures.length];
Stack<Integer> stack = new Stack<>();
for (int i = temperatures.length - 1; i >= 0; i--) {
while (!stack.empty() && temperatures[stack.peek()] <= temperatures[i]) {
stack.pop();
}
result[i] = stack.empty() ? 0 : stack.peek() - i;
stack.push(i);
}
return result;
}
}
Java:
class Solution {
public int[] nextGreaterElements(int[] nums) {
int[] result = new int[nums.length];
Stack<Integer> stack = new Stack<>();
for (int i = 2 * nums.length - 1; i >= 0; i--) {
while (!stack.empty() && stack.peek() <= nums[i % nums.length]) {
stack.pop();
}
result[i%nums.length] = stack.empty() ? -1 : stack.peek();
stack.push(nums[i % nums.length]);
}
return result;
}
}
Java:
class RandomizedSet {
public RandomizedSet() {
}
List<Integer> list = new ArrayList<Integer>();
Map<Integer, Integer> map = new HashMap<>();
public boolean insert(int value) {
// 若value 已经存在 ,不再插入
if (map.containsKey(value)) {
return false;
}
// 若value不存在,插入nums的尾部
// 并记录value对应的索引
map.put(value, list.size());
list.add(value);
return true;
}
public boolean remove(int value) {
// 若value不存在,不在删除
if (!map.containsKey(value)) {
return false;
}
// 先拿到value索引
int index = map.get(value);
// 交换到尾部
map.put(value, list.size() - 1);
map.put(list.get(list.size() - 1), index);
int temp = list.get(list.size() - 1);
list.set(list.size() - 1, value);
list.set(index, temp);
// 删除
map.remove(value);
list.remove(list.size() - 1);
return true;
}
public int getRandom() {
Random random = new Random();
int x = random.nextInt(list.size());
return list.get(x);
}
}
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet obj = new RandomizedSet();
* boolean param_1 = obj.insert(val);
* boolean param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/
] result = new int[temperatures.length];
Stack stack = new Stack<>();
for (int i = temperatures.length - 1; i >= 0; i--) {
while (!stack.empty() && temperatures[stack.peek()] <= temperatures[i]) {
stack.pop();
}
result[i] = stack.empty() ? 0 : stack.peek() - i;
stack.push(i);
}
return result;
}
}
###### [503. 下一个更大元素 II](https://leetcode-cn.com/problems/next-greater-element-ii/)
`Java:`
```java
class Solution {
public int[] nextGreaterElements(int[] nums) {
int[] result = new int[nums.length];
Stack stack = new Stack<>();
for (int i = 2 * nums.length - 1; i >= 0; i--) {
while (!stack.empty() && stack.peek() <= nums[i % nums.length]) {
stack.pop();
}
result[i%nums.length] = stack.empty() ? -1 : stack.peek();
stack.push(nums[i % nums.length]);
}
return result;
}
}
Java:
class RandomizedSet {
public RandomizedSet() {
}
List<Integer> list = new ArrayList<Integer>();
Map<Integer, Integer> map = new HashMap<>();
public boolean insert(int value) {
// 若value 已经存在 ,不再插入
if (map.containsKey(value)) {
return false;
}
// 若value不存在,插入nums的尾部
// 并记录value对应的索引
map.put(value, list.size());
list.add(value);
return true;
}
public boolean remove(int value) {
// 若value不存在,不在删除
if (!map.containsKey(value)) {
return false;
}
// 先拿到value索引
int index = map.get(value);
// 交换到尾部
map.put(value, list.size() - 1);
map.put(list.get(list.size() - 1), index);
int temp = list.get(list.size() - 1);
list.set(list.size() - 1, value);
list.set(index, temp);
// 删除
map.remove(value);
list.remove(list.size() - 1);
return true;
}
public int getRandom() {
Random random = new Random();
int x = random.nextInt(list.size());
return list.get(x);
}
}
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet obj = new RandomizedSet();
* boolean param_1 = obj.insert(val);
* boolean param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/
Study:
labuladong算法小抄