整数的反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
public int reverse(int x) {
long n = 0;
while(x != 0) {
n = n*10 + x%10; //数学公式
x = x/10;
}
return (int)n==n? (int)n:0; //将n强转为int类型 若强转不成功说明溢出 因为long类型是64位
}
删除数组中的重复项
一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
解题思路:使用快慢指针的思想
public int removeDuplicates(int[] nums) {
if (nums == null || nums.length == 1) {
return nums.length;
}
int j = 0;
for(int i=0;i<nums.length;i++){
if(nums [j]!=nums[i]){ //找不同的数值
nums [j+1]=nums[i];
j++;
}
}
return j + 1;
}
}
最小的k个数
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
思路:使用快排
快排:给定一个基准 高位 低位
若high大于基准 high-- 高位的值给低位
low小于基准 low++ 低位的值给高位
//快排的思想
private int[] quicksort(int[]arr,int high,int low,int val){
if (low >= high) {
return Arrays.copyOf(arr,val);
}
int mind=partition(arr,high,low);
if(low+1 <mind){
quicksort(arr,mind-1,low,val);
}
if(high-1 >mind){
quicksort(arr,high,mind+1,val);
}
return Arrays.copyOf(arr,val);
}
public int[] getLeastNumbers(int[] arr, int k) {
if(k==0||arr.length==0){
return new int[0];
}
return quicksort(arr,arr.length -1,0,k);
}
//因为是找最小的k个数 所以只用排序前k个数然后复制返回就好
private int[] quicksort(int[]arr,int high,int low,int val){
if (low >= high) {
return Arrays.copyOf(arr,val);
}
int mind=partition(arr,high,low);
if(mind == val) {
return Arrays.copyOf(arr, val);
}
return mind>val?quicksort(arr,mind-1,low,val):quicksort(arr,high,mind+1,val);
}
private int partition(int[] array, int high, int low){
int por=array[low];
while(low<high){
while (low < high && array[high] >= por) {
high--;
}
if(low==high){
break;
}
array[low]=array[high];
while (low < high && array[low] <= por) {
low++;
}
if(low==high){
break;
}
array[high]=array[low];
}
array[low] = por;
return low;
}
}
堆排 没快排速度快
大根堆
public int[] getLeastNumbers(int[] arr, int k) {
if(k==0||arr.length==0){
return new int[0];
}
//传自定义的比较器 默认是小根堆,实现大根堆需要重写一下比较器。
Queue<Integer> queue = new PriorityQueue<Integer>((o1, o2) ->o2-o1 );
for(int a:arr){
if(queue.size()<k){
queue.offer(a);
}else if(a<queue.peek()){
queue.poll();
queue.offer(a);
}
}
int [] ary=new int[k];
int idx=0;
for(int a:queue){
ary[idx++]=a;
}
return ary;
}
二叉搜索树
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0 || arr.length == 0) {
return new int[0];
}
// TreeMap的key是数字, value是该数字的个数。
// cnt表示当前map总共存了多少个数字。
TreeMap<Integer, Integer> map = new TreeMap<>();
int cnt = 0;
for (int num: arr) {
// 1. 遍历数组,若当前map中的数字个数小于k,则map中当前数字对应个数+1
if (cnt < k) {
map.put(num, map.getOrDefault(num, 0) + 1);
cnt++;
continue;
}
// 2. 否则,取出map中最大的Key(即最大的数字), 判断当前数字与map中最大数字的大小关系:
// 若当前数字比map中最大的数字还大,就直接忽略;
// 若当前数字比map中最大的数字小,则将当前数字加入map中,并将map中的最大数字的个数-1。
Map.Entry<Integer, Integer> entry = map.lastEntry();
if (entry.getKey() > num) {
map.put(num, map.getOrDefault(num, 0) + 1);
if (entry.getValue() == 1) {
map.pollLastEntry();
} else {
map.put(entry.getKey(), entry.getValue() - 1);
}
}
}
// 最后返回map中的元素
int[] res = new int[k];
int idx = 0;
for (Map.Entry<Integer, Integer> entry: map.entrySet()) {
int freq = entry.getValue();
while (freq-- > 0) {
res[idx++] = entry.getKey();
}
}
return res;
}
第一个只出现一次的字符串
s = “abaccdeff” 返回 “b”
s = “” 返回 " "
public char firstUniqChar(String s) {
for (int i = 0; i < s.length(); i++) {
char ch=s.charAt(i);
//首次出现的位置是当前位置,且后面没有再出现这个字符
if(s.indexOf(ch)==i&&s.indexOf(ch,i+1)==-1)
return s.charAt(i);
}
return ' ';
}
public char firstUniqChar(String s) {
Map<Character, Integer> map = new LinkedHashMap();
for(int i=0; i<s.length(); i++){
char c = s.charAt(i);
map.put(c, map.getOrDefault(c, 0)+1);
}
for(char ch: map.keySet()){
if(map.get(ch)==1)
return ch;
}
return ' ';
}
和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]
public int[] twoSum(int[] nums, int target) {
int prv=0;
int fast =nums.length-1;
while(prv<fast){
int sum =nums[prv]+nums[fast];
if(sum==target){
return new int[]{nums[prv],nums[fast]};
}
else if(sum>target){
fast--;
}else{
prv++;
}
}
return new int[0];
}
和为s的正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
输入:target = 9
输出:[[2,3,4],[4,5]]
思路:滑动窗口
public static int[][] findContinuousSequence(int target) {
List<int[]> list = new ArrayList<>();
for (int l = 1, r = 1, sum = 0; r < target; r++) {
sum += r;
while (sum > target) {
sum -= l++;
}
if (sum == target) {
int[] temp = new int[r - l + 1];
for (int i = 0; i < temp.length; i++) {
temp[i] = l + i;
}
list.add(temp);
}
}
int[][] res = new int[list.size()][];
for (int i = 0; i < res.length; i++) {
res[i] = list.get(i);
}
return res;
}
翻转单词
输入: “the sky is blue”
输出: “blue is sky the”
也就是说,trim()方法实际上的行为并不是”去掉两端的空白字符“,而是”截取中间的非空白字符“。
public String reverseWords(String s) {
//trim是截取中间的字符串 去掉两边的空格
String sc[]=s.trim().split(" ");
StringBuilder StringBudder=new StringBuilder();
for(int i=sc.length-1;i>=0;i--){
if (sc[i].equals("")) {
continue;
}
// 到头了,append然后去空格
if (i == 0) {
StringBudder.append(sc[i].trim());
} else {
// 怕有多余的空格,去掉,再加上去
StringBudder.append(sc[i].trim()).append(" ");
}
}return StringBudder.toString();
}
调整数组使得奇数在前
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一
public int[] exchange(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
while (left < right && nums[left] % 2 != 0) {
left++;
}
while (left < right && nums[right] % 2 == 0) {
right--;
}
if (left < right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
return nums;
}
第一次出现的字符
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
public char firstUniqChar(String s) {
for (int i = 0; i < s.length(); i++) {
char ch=s.charAt(i);
//首次出现的位置是当前位置,且后面没有再出现这个字符
if(s.indexOf(ch)==i&&s.indexOf(ch,i+1)==-1)
return s.charAt(i);
}
return ' ';
}
二进制中1的个数
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
思路:
根据 与运算 定义,设二进制数字 nn ,则有:
若 n & 1 = 0,则 n 二进制 最右一位 为 0 ;
若 n & 1 = 1 ,则 n 二进制 最右一位 为 1 。
根据以上特点,考虑以下 循环判断 :
判断 n 最右一位是否为 1 ,根据结果计数。
将 n 右移一位(本题要求把数字 n 看作无符号数,因此使用 无符号右移 操作)。
public int hammingWeight(int n) {
int res = 0;
while(n != 0) {
res += n & 1;
n >>>= 1;
}
return res;
}
思路2:
(n−1) 解析: 二进制数字 n 最右边的 1 变成 0 ,此 1 右边的 0 都变成 1 。
n & (n - 1) 解析: 二进制数字 n 最右边的 1 变成 0 ,其余不变。
public int hammingWeight(int n) {
int res = 0;
while(n != 0) {
res++;
n &= n - 1;
}
return res;
}
数组中出现次数超过数组长度一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
public int majorityElement(int[] nums) {
//getOrDefault(Object key, V defaultValue)
//这个判断是否含有key的键值对、若存在返回key的val,否则返回defaultValue
Map<Integer,Integer> map = new HashMap<>();
for(int num :nums){
map.put(num,map.getOrDefault(num,0)+1);
if(map.get(num)> nums.length>>1) return num;
}
return 0;
}
//若存在数大于数组一半的长度
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2]
}
//采用摩尔投票法
public int majorityElement(int[] nums) {
int count=0;
Integer vouat = null;
for(int num:nums){
if(count==0) vouat=num;
count +=(vouat==num)?1:-1;
}
}