剑指 Offer 10- II. 青蛙跳台阶问题
青蛙跳台问题,最开始的想法就是递归方法,但是是超时的
class Solution {
public int numWays(int n) {
if(n==1||n ==0){
return 1;
} else if (n == 2) {
return 2;
} else {
return (numWays(n - 1) + numWays(n - 2))%1000000007;
}
}
}
第二种就是循环求余法,有(a+b)%p = (a%p+b%p)%p的规则,所以也是一种递归的思路来解决。(有动态规划法,二刷※)
class Solution {
public int numWays(int n) {
int a = 1, b = 1, sum;
for(int i = 0; i < n; i++){
sum = (a + b) % 1000000007;
a = b;
b = sum;
}
return a;
}
}
剑指 Offer 15. 二进制中1的个数
本题主要是考的对于运算符的理解和使用,做起来挺绕的,而且也是第一个做相应的题型。
第一种的思路是((n&(1<<i))!=0),用n和n的相应位置为1时做与运算,如果是1,结果不为0,1的个数加一。
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int ret = 0;
for(int i=0;i<32;i++){
if ((n & (1 << i)) != 0)
ret++;
}
}
return ret;
}
}
还有很多的方法来解决,比如用tar += n&1 n>>>1;每次tar加0或1,然后n右移一位。和上面的类似,一个是1动,一个是1不动。
public class Solution {
public int hammingWeight(int n) {
int res = 0;
while(n != 0) {
res += n & 1;
n >>>= 1;
}
return res;
}
}
第三种当时也是想了很久,核心为 while(n != 0) { res++; n &= n - 1; },n不为0,即n包含1,先加,然后n&=n-1,就是每次把最后一个1消掉,当时就是这一点,忽略了那个等于好,直接犯傻了。每种思路都会让我醒悟,也确实学到了!
public class Solution {
public int hammingWeight(int n) {
int res = 0;
while(n != 0) {
res++;
n &= n - 1;
}
return res;
}
}
剑指 Offer 17. 打印从1到最大的n位数
又是到了能用到暴力法的了,只能说难题我畏畏缩缩,只会cv,简单题我必重拳出击。
先一个循环把需要打印的数范围扩大到10^n。然后就是最喜欢的依次遍历了插入了。
class Solution {
public int[] printNumbers(int n) {
int t = 1;
for(int i = 0;i<n;i++){
t *= 10;
}
int[] a = new int[t-1];
for(int i=1;i<t;i++){
a[i-1] = i;
}
return a;
}
}
然后对于次方的计算,也是有相对的函数的,显然这样看起来比较简洁。
int end = (int)Math.pow(10, n) - 1;
这一题也就是一个全排列问题,但是还没有一点思路。
剑指 Offer 18. 删除链表的节点
感觉有段时间没有刷到链表题了,这一题也就是基本的链表的删除,只要注意特殊情况,并且在找到删除值的时候,让其前一个的next指向其本身的next即可。(单指针)
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if(head == null){
return null;
}
if(head.val == val){
return head.next;
}
ListNode cur = head;
while(cur.next != null && cur.next.val != val){
cur = cur.next;
}
if(cur.next!=null){ //这一处是判断cur.next不为空,就是找到要删除的节点,
//但是本题来说,不是必要,因为删除结点存在。
cur.next = cur.next.next;
}
return head;
}
(双指针)相对于单个指针,更好去看明白删除的过程。
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if(head == null){
return null;
}
if(head.val == val){
return head.next;
}
ListNode pre = head, cur = head.next;
while(cur != null && cur.val != val){
pre = cur;
cur = cur.next;
}
if(cur!=null){
pre.next = cur.next;
}
else{
}
return head;
}
}
if(cur!=null)
其实对于这句话,我刚开始是不理解的,我一直在想,上面的while已经判断过了,那肯定就是找到了val,然后我改成了cur.next!=null;但是忽略了如果找到的元素在最后,那就无解了,也是困扰了挺久,最后所幸理解透了。
566. 重塑矩阵
再怎么重塑矩阵,首先他的m*n是永远等于新的长度r*c的。第一种想法,显然是双重循环输出新数组,而对其判定就是先对其列增加,当达到原矩阵列的长度时,置0,行增加。
class Solution {
public int[][] matrixReshape(int[][] mat, int r, int c) {
int m = mat.length;
int n = mat[0].length;
if(m * n != r * c){
return mat;
}
int[][] a = new int[r][c];
int x = 0;
int y = 0;
for(int i = 0;i<r;i++)
{
for(int j = 0;j<c;j++){
a[i][j] = mat[x][y];
y++;
if(y>=n){
y=0;
x++;
}
}
}
return a;
}
}
第二种的输出就很巧妙,是一种映射的方法,做除运算和余运算来更新数组坐标。
class Solution {
public int[][] matrixReshape(int[][] mat, int r, int c) {
int m = mat.length;
int n = mat[0].length;
if(m * n != r * c){
return mat;
}
int[][] ans = new int[r][c];
for(int i = 0;i<m*n;i++)
{
ans[i / c][i % c] = mat[i / n][i % n];
}
return ans;
}
}
正巧还看到一个哈希表的方法,便自己模仿着写了一遍,对于哈希表的使用也算是熟悉了的,就是有点不大明白为啥空间和时间变化挺大的。
class Solution {
public int[][] matrixReshape(int[][] mat, int r, int c) {
int m = mat.length;
int n = mat[0].length;
int t = 0;
if(m * n != r * c){
return mat;
}
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < m; i++)
{
for(int j = 0;j < n; j++){
map.put(t++, mat[i][j]);
}
}
int[][] ans = new int[r][c];
for(int i = 0;i < r;i++)
{
for(int j = 0;j < c;j++)
{
ans[i][j] = map.get(i*c+j);
}
}
return ans;
}
}
118. 杨辉三角
杨辉三角问题,其实在大一学c++就接触了,记得当时还是一个考试热门题呢,就是迭代递归问题,求左上角和右上角的和为当前插入的元素值。就是第一次遇到List<List<Integer>>的用法,比二维数组方便多了。
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
for(int i = 0;i<numRows;i++){
List<Integer> row = new ArrayList<Integer>();
for(int j = 0;j<=i;j++){
if(j==0||j==i)
{
row.add(1);
}
else
{
row.add(ret.get(i - 1).get(j - 1) + ret.get(i - 1).get(j));
}
}
ret.add(row);
}
return ret;
}
}
也做了递归法,但是超时了。
class Solution {
public List<List<Integer>> generate(int numRows)
{
List<List<Integer>> ret = new ArrayList<List<Integer>>();
for (int i = 0; i < numRows; i++) {
List<Integer> row = new ArrayList<Integer>();
for (int j = 0; j <=i; j++) {
row.add(generate_1(i, j));
}
ret.add(row);
}
return ret;
}
private int generate_1(int i, int j) {
int result = 0;
if (j == 0 || j == i) {
result = 1;
}
else {
result =(generate_1(i - 1, j - 1) + generate_1(i - 1, j));
}
return result;
}
}