剑指offer
时隔一年重新开始剑指offer,争取月底之前做完剑指吧,做个小记录。
Easy
- 03 数组中的重复数字
可以用HashMap,比较简单,在评论区看到一种比较好的办法,记录一下
public int findRepeatNumber(int[] nums) {
int n = nums.length;
for (int i = 0;i < n;i ++){
int cur = nums[i];
if(cur < 0){
cur = cur + n;
}
if(nums[cur]<0){
return cur;
}
nums[i] = nums[i] - n;
}
return -1;
}
- 05 替换空格
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()){
if(c==' ') {
sb.append("%20");
}else{
sb.append(c);
}
}
return sb.toString();
}
- 06 从尾到头打印链表
用栈就行了
public int[] reversePrint(ListNode head) {
Stack<ListNode> stack = new Stack<>();
int count = 0;
while (head!=null) {
stack.push(head);
head = head.next;
count++;
}
int[] result = new int[count];
count = 0;
while (!stack.isEmpty()) {
result[count++] = stack.pop().val;
}
return result;
}
- 09 用两个栈实现队列
class CQueue {
/**
* 前
* */
private Stack<Integer> s1;
/**
* 后
* */
private Stack<Integer> s2;
public CQueue() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public void appendTail(int value) {
s2.push(value);
}
public int deleteHead() {
if (!s1.isEmpty()){
return s1.pop();
}
while(!s2.isEmpty())
{
s1.push(s2.pop());
}
return s1.isEmpty()?-1:s1.pop();
}
}
- 10 斐波拉契
简单dp
public static int fib(int n) {
if(n<=1)
{
return n;
}
int[] nums = new int[n+1];
nums[0] = 0;
nums[1] = 1;
for (int i = 2;i <= n;i++)
{
nums[i] = nums[i-1]+nums[i-2];
}
return nums[n];
}
- 11 青蛙跳台阶
和上面类似
public static int numWays(int n) {
if(n==0||n==1)
{
return 1;
}
int[] v = new int[n+1];
v[0] = 1;
v[1] = 1;
v[2] = 2;
for (int i = 3;i <= n ;i++)
{
v[i] = (v[i-1]+v[i-2])%(1000000007);
}
return v[n];
}
- 11 旋转数组的最小数字
转为二分查找比较合适,但是需要变通一下。
public static int minArray(int[] numbers) {
int left = 0;
int right = numbers.length-1;
int mid;
if(numbers[left]<numbers[right])
{
return numbers[left];
}
while (left<right)
{
if(numbers[left]<numbers[right])
{
return numbers[left];
}
mid = left + (right - left) / 2;
if(numbers[mid] < numbers[right])
{
right = mid;
}
else if(numbers[mid] > numbers[right])
{
left = mid + 1;
}
else
{
right--;
}
}
return numbers[left];
}
- 15 二进制中1的个数
第一种办法,比较容易想到,模拟我们手动求数字二进制形式的过程即可,不断取2的模,然后计数,但需要注意的是,这里n是无符号数,最高位不做符号位,而是数字位,那么符号右移的时候,需要采用java的>>>来进行运算,因为对于有符号的右移,n为负数的时候,最高位会补1,反之补0,但这里n是无符号数,所以这里只能采取无符号右移,也就是默认补0,此外,对于循环的终止条件,不应该用n>0,因为n可能为负数。
public int hammingWeight(int n) {
int count = 0;
int num = n;
while (num != 0 ){
int t = num & 1;
count = count + t;
num = num >>> 1;
}
return count;
}
第二种办法比较巧,相比于第一种办法突出的地方在于,循环次数减少,因为这里我们只需要计算1的个数,而其余位数的0我们并不在乎,所以可以用n&(n-1)来消去最右边的1,这样循环次数就变成了1的个数。
public static int hammingWeight(int n) {
int count = 0;
int num = n;
while (num != 0 ){
int t = num & 1;
count = count + t;
num = num >>> 1;
}
return count;
}