4.29 二轮 数组

This commit is contained in:
zhangsan 2025-04-29 16:19:09 +08:00
parent 1cfbdd2b5c
commit 19b61ceb96
13 changed files with 562 additions and 0 deletions

View File

@ -0,0 +1,30 @@
package array;
import java.util.Arrays;
/**
* 题目 274. H 指数 (hIndex)
* 描述给你一个整数数组 citations 其中 citations[i] 表示研究者的第 i 篇论文被引用的次数计算并返回该研究者的 h 指数
* 根据维基百科上 h 指数的定义h 代表高引用次数 一名科研人员的 h 指数 是指他至少发表了 h 篇论文并且 至少 h 篇论文被引用次数大于等于 h 如果 h 有多种可能的值h 指数 是其中最大的那个
*
* 示例 1
输入citations = [3,0,6,1,5]
输出3
解释给定数组表示研究者总共有 5 篇论文每篇论文相应的被引用了 3, 0, 6, 1, 5
由于研究者有 3 篇论文每篇 至少 被引用了 3 其余两篇论文每篇被引用 不多于 3 所以她的 h 指数是 3
* 链接https://leetcode.cn/problems/h-index/
*/
public class HIndex {
//根据 H 指数的定义如果当前 H 指数为 h 并且在遍历过程中找到当前值 citations[i]>h则说明我们找到了一篇被引用了至少 h+1 次的论文
//所以将现有的 h 值加 1继续遍历直到 h 无法继续增大最后返回 h 作为最终答案
public int hIndex(int[] citations) {
Arrays.sort(citations);
int h = 0, i = citations.length - 1;
while (i >= 0 && citations[i] > h) {
h++;
i--;
}
return h;
}
}

View File

@ -0,0 +1,53 @@
package array;
import java.util.*;
/**
* 题目 12. 整数转罗马数字 (intToRoman)
* 描述罗马数字是通过添加从最高到最低的小数位值的转换而形成的将小数位值转换为罗马数字有以下规则
* 符号
* I 1
* V 5
* X 10
* L 50
* C 100
* D 500
* M 1000
* 如果该值不是以 4 9 开头请选择可以从输入中减去的最大值的符号将该符号附加到结果减去其值然后将其余部分转换为罗马数字
* 如果该值以 4 9 开头使用 减法形式表示从以下符号中减去一个符号例如 4 5 (V) 1 (I): IV 9 10 (X) 1 (I)IX仅使用以下减法形式4 (IV)9 (IX)40 (XL)90 (XC)400 (CD) 900 (CM)
* 只有 10 的次方I, X, C, M最多可以连续附加 3 次以代表 10 的倍数你不能多次附加 5 (V)50 (L) 500 (D)如果需要将符号附加4次请使用 减法形式
* 给定一个整数将其转换为罗马数字
*
* 示例 1
输入num = 3749
输出 "MMMDCCXLIX"
解释
3000 = MMM 由于 1000 (M) + 1000 (M) + 1000 (M)
700 = DCC 由于 500 (D) + 100 (C) + 100 (C)
40 = XL 由于 50 (L) 10 (X)
9 = IX 由于 10 (X) 1 (I)
注意49 不是 50 (L) 1 (I) 因为转换是基于小数位
* 链接https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
*/
public class IntToRoman {
int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String[] symbols = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
public String intToRoman(int num) {
StringBuffer roman = new StringBuffer();
for (int i = 0; i < values.length; ++i) {
int value = values[i];
String symbol = symbols[i];
while (num >= value) {
num -= value;
roman.append(symbol);
}
if (num == 0) {
break;
}
}
return roman.toString();
}
}

View File

@ -0,0 +1,45 @@
package array;
/**
* 题目 58. 最后一个单词的长度 (lengthOfLastWord)
* 描述给你一个字符串 s由若干单词组成单词前后用一些空格字符隔开返回字符串中 最后一个 单词的长度
*
* 单词 是指仅由字母组成不包含任何空格字符的最大子字符串
*
* 示例 1
输入s = "Hello World"
输出5
解释最后一个单词是World长度为 5
* 链接https://leetcode.cn/problems/length-of-last-word/
*/
public class LengthOfLastWord {
public int lengthOfLastWord(String s) {
int total=s.length();
int begin=-1,end=total;
for (int i = total-1; i >=0.; i--) {
char cur=s.charAt(i);
if(end==total&&cur==' ') {
}
else if(end == total) end=i;
else {
if (cur == ' ') {
begin = i;
break;
}
}
}
return end-begin;
}
public int lengthOfLastWord2(String s) {
int index = s.length() - 1;
while (s.charAt(index) == ' ') {
index--;
}
int wordLength = 0;
while (index >= 0 && s.charAt(index) != ' ') {
wordLength++;
index--;
}
return wordLength;
}
}

View File

@ -0,0 +1,32 @@
package array;
/**
* 题目 14. 最长公共前缀 (longestCommonPrefix)
* 描述编写一个函数来查找字符串数组中的最长公共前缀
* 如果不存在公共前缀返回空字符串 ""
*
* 示例 1
输入strs = ["flower","flow","flight"]
输出"fl"
* 链接https://leetcode.cn/problems/longest-common-prefix/
*/
public class LongestCommonPrefix {
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) {
return "";
}
int length = strs[0].length();
int count = strs.length;
for (int i = 0; i < length; i++) {
char c = strs[0].charAt(i);
for (int j = 1; j < count; j++) {
if (i == strs[j].length() || strs[j].charAt(i) != c) {
return strs[0].substring(0, i);
}
}
}
return strs[0];
}
}

View File

@ -0,0 +1,40 @@
package array;
/**
* 题目 88. 合并两个有序数组 (merge)
* 描述给你两个按 非递减顺序 排列的整数数组 nums1 nums2另有两个整数 m n 分别表示 nums1 nums2 中的元素数目
* 请你 合并 nums2 nums1 使合并后的数组同样按 非递减顺序 排列
* 注意最终合并后数组不应由函数返回而是存储在数组 nums1 为了应对这种情况nums1 的初始长度为 m + n其中前 m 个元素表示应合并的元素 n 个元素为 0 应忽略nums2 的长度为 n
* 示例 1
输入nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出[1,2,2,3,5,6]
解释需要合并 [1,2,3] [2,5,6]
合并结果是 [1,2,2,3,5,6] 其中斜体加粗标注的为 nums1 中的元素
* 链接https://leetcode.cn/problems/merge-sorted-array/
*/
public class Merge1 {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int[]temp=new int[m+n];
int i=0,j=0,k=0;
while (i<m&&j<n){
if(nums1[i]<=nums2[j]) {
temp[k] = nums1[i];
i++;
}
else {
temp[k] = nums2[j];
j++;
}
k++;
}
while(i<m){
temp[k++]=nums1[i++];
}
while (j<n){
temp[k++]=nums2[j++];
}
if (m + n >= 0) System.arraycopy(temp, 0, nums1, 0, m + n);
}
}

View File

@ -0,0 +1,71 @@
package array;
import java.util.*;
/**
* 题目 380. O(1) 时间插入删除和获取随机元素 (RandomizedSet)
* 描述实现RandomizedSet
* RandomizedSet() 初始化 RandomizedSet 对象
* bool insert(int val) 当元素 val 不存在时向集合中插入该项并返回 true 否则返回 false
* bool remove(int val) 当元素 val 存在时从集合中移除该项并返回 true 否则返回 false
* int getRandom() 随机返回现有集合中的一项测试用例保证调用此方法时集合中至少存在一个元素每个元素应该有 相同的概率 被返回
* 你必须实现类的所有函数并满足每个函数的 平均 时间复杂度为 O(1) *
*
* 示例 1
输入
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出
[null, true, false, true, 2, true, false, 2]
解释
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // 向集合中插入 1 返回 true 表示 1 被成功地插入
randomizedSet.remove(2); // 返回 false 表示集合中不存在 2
randomizedSet.insert(2); // 向集合中插入 2 返回 true 集合现在包含 [1,2]
randomizedSet.getRandom(); // getRandom 应随机返回 1 2
randomizedSet.remove(1); // 从集合中移除 1 返回 true 集合现在包含 [2]
randomizedSet.insert(2); // 2 已在集合中所以返回 false
randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字getRandom 总是返回 2
* 链接https://leetcode.cn/problems/insert-delete-getrandom-o1/
*/
class RandomizedSet {
List<Integer> nums;
Map<Integer, Integer> indices;
Random random;
public RandomizedSet() {
nums = new ArrayList<Integer>();
indices = new HashMap<Integer, Integer>();
random = new Random();
}
public boolean insert(int val) {
if (indices.containsKey(val)) {
return false;
}
int index = nums.size();
nums.add(val);
indices.put(val, index);
return true;
}
public boolean remove(int val) {
if (!indices.containsKey(val)) {
return false;
}
int index = indices.get(val);
int last = nums.get(nums.size() - 1);
nums.set(index, last);
indices.put(last, index);
nums.remove(nums.size() - 1);
indices.remove(val);
return true;
}
public int getRandom() {
int randomIndex = random.nextInt(nums.size());
return nums.get(randomIndex);
}
}

View File

@ -0,0 +1,73 @@
package array;
/**
* 题目 26. 删除有序数组中的重复项 (removeDuplicates)
* 描述给你一个 非严格递增排列 的数组 nums 请你 原地 删除重复出现的元素使每个元素 只出现一次 返回删除后数组的新长度元素的 相对顺序 应该保持 一致 然后返回 nums 中唯一元素的个数
* 考虑 nums 的唯一元素的数量为 k 你需要做以下事情确保你的题解可以被通过
* 更改数组 nums 使 nums 的前 k 个元素包含唯一元素并按照它们最初在 nums 中出现的顺序排列nums 的其余元素与 nums 的大小不重要
* 返回 k
*
* 示例 1
输入nums = [1,1,2]
输出2, nums = [1,2,_]
解释函数应该返回新的长度 2 并且原数组 nums 的前两个元素被修改为 1, 2 不需要考虑数组中超出新长度后面的元素
* 链接https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
*/
public class RemoveDuplicates {
//很啰嗦
public int removeDuplicates2(int[] nums) {
int pre=0,deleted=0,start=0,invalid=Integer.MIN_VALUE;
for (int i = 1; i < nums.length; i++) {
if(nums[i]==nums[pre]) {
nums[i] = invalid;
deleted++;
}
else
pre=i;
}
for (int i = 1; i < nums.length-deleted; i++) {
if(nums[i]==invalid){
int j;
if(start==0)
j=i+1;
else
j=start;
while (j<nums.length){
if(nums[j]!=invalid) {
nums[i] = nums[j];
nums[j]=invalid;
start=j+1;
break;
}
j++;
}
}
}
return nums.length-deleted;
}
//双指针
/**
* 我们可以直接用双指针在一次遍历里完成所有操作
*
* 慢指针 write指向下一个要写入唯一元素的位置
* 快指针 read扫描整个数组
* nums[read] != nums[read - 1] 就把它写到 nums[write++]
* @param nums
* @return
*/
public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
// write 指向下一次写入的位置初始写 nums[0]
int write = 1;
// read 1 开始扫描到末尾
for (int read = 1; read < nums.length; read++) {
// 只有当遇到新值时才写入并推进 write
if (nums[read] != nums[read - 1]) {
nums[write] = nums[read];
write++;
}
}
return write;
}
}

View File

@ -0,0 +1,45 @@
package array;
/**
* 题目 80. 删除有序数组中的重复项 II (removeDuplicates)
* 描述给你一个有序数组 nums 请你 原地 删除重复出现的元素使得出现次数超过两次的元素只出现两次 返回删除后数组的新长度
* 不要使用额外的数组空间你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成
*
* 示例 1
输入nums = [1,1,1,2,2,3]
输出5, nums = [1,1,2,2,3]
解释函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 不需要考虑数组中超出新长度后面的元素
* 链接https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/
*/
public class RemoveDuplicates2 {
//自己写的
public int removeDuplicates(int[] nums) {
int tpcnt=1,prenum=nums[0],write=0;
for (int i = 1; i < nums.length; i++) {
if(nums[i]==prenum){
tpcnt++;
}else{
tpcnt=1;
prenum=nums[i];
}
if(tpcnt<=2) {
write++;
nums[write] = nums[i];
}
}
return write+1;
}
//标准答案
public int removeDuplicates2(int[] nums) {
if (nums.length <= 2) return nums.length;
int write = 2; // 已保留的区间长度至少为 2
for (int i = 2; i < nums.length; i++) {
// 只要当前 nums[i] 跟已经保留区的倒数第 2 个不同就可以写入
if (nums[i] != nums[write - 2]) {
nums[write] = nums[i];
write++;
}
}
return write;
}
}

View File

@ -0,0 +1,58 @@
package array;
/**
* 题目 27. 移除元素 (removeElement)
* 描述给你一个数组 nums 和一个值 val你需要 原地 移除所有数值等于 val 的元素元素的顺序可能发生改变然后返回 nums 中与 val 不同的元素的数量
* 假设 nums 中不等于 val 的元素数量为 k要通过此题您需要执行以下操作
* 更改 nums 数组使 nums 的前 k 个元素包含不等于 val 的元素nums 的其余元素和 nums 的大小并不重要
* 返回 k
*
*
* 示例 1
输入nums = [3,2,2,3], val = 3
输出2, nums = [2,2,_,_]
解释你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2
你在返回的 k 个元素之外留下了什么并不重要因此它们并不计入评测
* 链接https://leetcode.cn/problems/remove-element/
*/
public class RemoveElement {
public int removeElement1(int[] nums, int val) {
int n=nums.length,chosen=0;
for (int i = 0; i < n; i++) {
if(nums[i]==val) {
nums[i] = -1;
chosen++;
}
}
for (int i = 0; i < n-chosen; i++) {
if(nums[i]==-1){
for (int j = n-1; j > i; j--) {
if(nums[j]!=-1) {
nums[i] = nums[j];
nums[j]=-1;
break;
}
}
}
}
return n-chosen;
}
//双指针
public int removeElement(int[] nums, int val) {
int i = 0, j = nums.length - 1;
while (i <= j) {
if (nums[i] == val) {
// 把尾部的元素换到 i 位置
nums[i] = nums[j];
// 尾部换下来的这个位置无论是不是 val都算处理过了
j--;
} else {
// nums[i] 本身就不是 val保留继续往前
i++;
}
}
// i 最终停在第一个应该被移除的位置
// 也就是有 i 个非 val 元素
return i;
}
}

View File

@ -0,0 +1,60 @@
package array;
import java.util.HashMap;
import java.util.Map;
/**
* 题目 13. 罗马数字转整数 (romanToInt)
* 描述罗马数字包含以下七种字符: I V X LCD M
* 字符 数值
* I 1
* V 5
* X 10
* L 50
* C 100
* D 500
* M 1000
* 例如 罗马数字 2 写做 II 即为两个并列的 1 12 写做 XII 即为 X + II 27 写做 XXVII, 即为 XX + V + II
*
* 通常情况下罗马数字中小的数字在大的数字的右边但也存在特例例如 4 不写做 IIII而是 IV数字 1 在数字 5 的左边所表示的数等于大数 5 减小数 1 得到的数值 4 同样地数字 9 表示为 IX这个特殊的规则只适用于以下六种情况
*
* I 可以放在 V (5) X (10) 的左边来表示 4 9
* X 可以放在 L (50) C (100) 的左边来表示 40 90
* C 可以放在 D (500) M (1000) 的左边来表示 400 900
* 给定一个罗马数字将其转换成整数
*
* 示例 1
输入: s = "III"
输出: 3
示例 5:
输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
* 链接https://leetcode.cn/problems/roman-to-integer/
*/
public class RomanToInt {
Map<Character, Integer> symbolValues = new HashMap<Character, Integer>() {{
put('I', 1);
put('V', 5);
put('X', 10);
put('L', 50);
put('C', 100);
put('D', 500);
put('M', 1000);
}};
//左边的数比右边的小就减法
public int romanToInt(String s) {
int ans = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
int value = symbolValues.get(s.charAt(i));
if (i < n - 1 && value < symbolValues.get(s.charAt(i + 1))) {
ans -= value;
} else {
ans += value;
}
}
return ans;
}
}

View File

@ -0,0 +1,20 @@
package array;
import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.*;
public class Merge1Test {
@Test
public void merge() {
int[] nums1 = {1,2,3,0,0,0};
int m = 3,n=3;
int[] nums2 = {2,5,6};
Merge1 solution = new Merge1();
solution.merge(nums1,m,nums2,n);
System.out.println(Arrays.toString(nums1));
}
}

View File

@ -0,0 +1,19 @@
package array;
import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.*;
public class RemoveDuplicatesTest {
@Test
public void removeDuplicates() {
RemoveDuplicates solution = new RemoveDuplicates();
int[] nums = {-3,-1,0,0,0,3,3};
int res=solution.removeDuplicates(nums);
System.out.println(res);
System.out.println(Arrays.toString(nums));
}
}

View File

@ -0,0 +1,16 @@
package array;
import org.junit.Test;
import static org.junit.Assert.*;
public class RemoveElementTest {
@Test
public void removeElement() {
int[]nums={3,2,2,3};
int val=3;
RemoveElement solution = new RemoveElement();
solution.removeElement(nums,val);
}
}