算法题存档20191223

题目描述

删除给出链表中的重复元素,使链表中的所有元素都只出现一次

例如:

给出的链表为1->1->2,返回1->2.

给出的链表为1->1->2->3->3,返回1->2->3.

public class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        }
        ListNode first = new ListNode(-1);
        first.next = head;
        ListNode pre = first;
        ListNode now = head;
        while(now != null && now.next != null){
            pre = now;
            if(now.val == now.next.val){
                while(now.next != null && now.val == now.next.val) {
                    now = now.next;
                }
                pre.next = now.next;
            }
            now = now.next;
        }
        return first.next;
    }
}

题目描述

给出一个二维字符数组和一个单词,判断单词是否在数组中出现,

单词由相邻单元格的字母连接而成,相邻单元指的是上下左右相邻。同一单元格的字母不能多次使用。

例如:

给出的字符数组=

[↵  ["ABCE"],↵  ["SFCS"],↵  ["ADEE"]↵]
public class Solution {
    public boolean exist(char[][] board, String word) {
        int m = board.length;
        int n = board[0].length;

        boolean[][] visited = new boolean[m][n];

        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j ++ ) {
                if(deep(board, word, visited, i, j, 0, m, n)) {
                    return true;
                }
            }
        }

        return false;
    }
    
    private boolean deep(char[][] board, String word,  boolean[][] visited, int i, int j, int count, int m, int n) {
        if(count == word.length()) {
            return true;
        }
        if(i < 0 || i >= m || j < 0 || j >= n || board[i][j] != word.charAt(count) || visited[i][j]) {
            return false;
        }
        visited[i][j] = true;
        boolean res = deep(board, word, visited, i - 1, j, count + 1, m, n) ||
                deep(board, word, visited, i + 1, j, count + 1, m, n) ||
                deep(board, word, visited, i, j - 1, count + 1, m, n) ||
                deep(board, word, visited, i, j + 1, count + 1, m, n);
        visited[i][j] = false;

        return res;
    }
}

题目描述

给出两个整数n和k,返回从1到n中取k个数字的所有可能的组合

例如:

如果n=4,k=2,结果为

[↵  [2,4],↵  [3,4],↵  [2,3],↵  [1,2],↵  [1,3],↵  [1,4],↵]
public class Solution {
    ArrayList<ArrayList<Integer>> result;

    public ArrayList<ArrayList<Integer>> combine(int n, int k) {
        result = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> temp = new ArrayList<Integer>();

        if(n < 1 || k < 1 || n < k) {
            return result;
        }

        combine(n, k, 1, temp);

        return result;
    }

    private void combine(int n, int k, int index, ArrayList<Integer> tem) {
        if(tem.size() == k) {
            result.add(new ArrayList<>(tem));
            return;
        }

        if(index > n) {
            return;
        } else {
            int left = k - tem.size() - 1;
            for (int i = index; i <= n - left; i++) {
                tem.add(i);
                combine(n, k, i + 1, tem);
                tem.remove(tem.size() - 1);
            }
        }

    }
}

题目描述

给出两个字符串S和T,要求在O(n)的时间复杂度内在S中找出最短的包含T中所有字符的子串。

例如:

S ="ADOBECODEBANC"
T ="ABC"

找出的最短子串为"BANC".

注意:

如果S中没有包含T中所有字符的子串,返回空字符串 “”;

满足条件的子串可能有很多,但是题目保证满足条件的最短的子串唯一。

public class Solution {
    public String minWindow(String S, String T) {
        int[] map = new int[128];
        for(int i = 0; i < T.length(); i++) {
            map[T.charAt(i)]++;
        }

        int left = 0;
        int right = 0;
        int result = Integer.MAX_VALUE;
        int counter = T.length();
        int head = 0;
        while(right < S.length()) {
            if(map[S.charAt(right++)]-- > 0) {
                counter--;
            }
            while (counter == 0) {
                if(right - left < result) {
                    head = left;
                    result = right - left;
                }
                if(map[S.charAt(left++)]++ == 0) {  
                    counter++;                     
                }
            }
        }
        return result == Integer.MAX_VALUE ? "" : S.substring(head, head + result);
    }
}

题目描述

现在有一个包含n个物体的数组,其中物体颜色为颜色为红色、白色或蓝色,请对这个数组进行排序,让相同颜色的物体相邻,颜色的顺序为红色,白色,蓝色。

我们用0,1,2分别代表颜色红,白,蓝

注意:

本题要求你不能使用排序库函数

扩展:

一个非常直接的解法是两步的计数排序的算法

首先:遍历一遍数组,记录0,1,2的数量,然后重写这个数组,先将0写入,再将1写入,再将2写入

你能给出一个只用一步,并且能在常数级空间复杂度解决这个问题的算法吗?

public class Solution {
    public void sortColors(int[] A) {
        int zero = 0;
        int two = A.length - 1;

        for(int i = 0; i <= two; i++) {
            if(A[i] == 0) {
                A[i] = A[zero];
                A[zero++] = 0;
            } else if(A[i] == 2) {
                A[i] = A[two];
                A[two] = 2;
                i--;
                two--;
            }
        }
    }
}

题目描述

请写出一个高效的在m*n矩阵中判断目标值是否存在的算法,矩阵具有如下特征:

每一行的数字都从左到右排序

每一行的第一个数字都比上一行最后一个数字大

例如:

对于下面的矩阵:

[↵  [1,   3,  5,  7],↵  [10, 11, 16, 20],↵  [23, 30, 34, 50]↵]

要搜索的目标值为3,返回true;

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;
        int i = 0;
        for(; i < m; i++) {
            if(matrix[i][0] == target) {
                return true;
            } else if(matrix[i][0] > target) {
                break;
            }
        }
        if(i == 0) {
            return false;
        }
        for(int j = 0; j < n; j++) {
            if(matrix[i - 1][j] == target) {
                return true;
            } else if(matrix[i - 1][j] > target) {
                return false;
            }
        }
        return false;
    }
}

题目描述

给定一个m*n的矩阵,如果有一个元素是0,就把该元素所在的行和列上的元素全置为0,要求使用原地算法。

拓展:

你的算法有使用额外的空间吗?

一种比较直接的算法是利用O(m,n)的空间,但是这不是一个好的解法

使用简单的改进可以在O(m+n)的空间解决这个问题,但是还不是最佳的解法

你能在常量级的空间复杂度内解决这个问题吗?

public class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;

        boolean nZero = false;
        boolean mZero = false;
        for(int i = 0; i < n; i++) {
           if(matrix[0][i] == 0) {
               nZero = true;
               break;
           }
        }
        for(int i = 0; i < m; i++) {
            if(matrix[i][0] == 0) {
                mZero = true;
                break;
            }
        }

        for(int i = 1; i < m; i++) {
            for(int j = 1; j < n; j++) {
                if(matrix[i][j] == 0) {
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (0 == matrix[i][0] || 0 == matrix[0][j]) {
                    matrix[i][j] = 0;
                }
            }
        }

        if (nZero)
            for (int i = 0; i < n; i++) {
                matrix[0][i] = 0;
            }
        if (mZero)
            for (int i = 0; i < m; i++)
                matrix[i][0] = 0;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值